|
From: Peter P. <pr...@us...> - 2006-11-23 23:22:51
|
Update of /cvsroot/pyxida/Pyxida/src/edu/harvard/syrah/pyxida/ping In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27812/src/edu/harvard/syrah/pyxida/ping Modified Files: TCPSynPinger.java ICMPPinger.java Pinger.java Added Files: JpcapPinger.java Removed Files: JPCapPinger.java Log Message: More work on Pingers. I ran into an issue where I can't convince libpcap to return from packet capture after a given timeout. This appears to be a known issues under Linux. Unfortunately, this means that I'll have to change the overall structure of JpcapPinger. --- JPCapPinger.java DELETED --- Index: Pinger.java =================================================================== RCS file: /cvsroot/pyxida/Pyxida/src/edu/harvard/syrah/pyxida/ping/Pinger.java,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** Pinger.java 22 Nov 2006 18:46:44 -0000 1.1 --- Pinger.java 23 Nov 2006 23:22:48 -0000 1.2 *************** *** 1,4 **** --- 1,5 ---- package edu.harvard.syrah.pyxida.ping; + import edu.harvard.syrah.sbon.async.CallbacksIF.CB1; import edu.harvard.syrah.sbon.comm.AddressIF; *************** *** 7,15 **** protected AddressIF localAddr; protected AddressIF defaultPingAddr; ! ! protected Thread thread; protected boolean shutdown = false; - } --- 8,21 ---- protected AddressIF localAddr; protected AddressIF defaultPingAddr; ! ! //protected Thread thread; protected boolean shutdown = false; + class PingData { + AddressIF pingAddr; + double lat; + CB1<Double> cbLat; + } + } Index: TCPSynPinger.java =================================================================== RCS file: /cvsroot/pyxida/Pyxida/src/edu/harvard/syrah/pyxida/ping/TCPSynPinger.java,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** TCPSynPinger.java 23 Nov 2006 16:46:10 -0000 1.3 --- TCPSynPinger.java 23 Nov 2006 23:22:48 -0000 1.4 *************** *** 6,10 **** import edu.harvard.syrah.sbon.comm.AddressIF; ! class TCPSynPinger extends JPCapPinger implements PingerIF { private static final Log log = new Log(TCPSynPinger.class); --- 6,10 ---- import edu.harvard.syrah.sbon.comm.AddressIF; ! class TCPSynPinger extends JpcapPinger implements PingerIF { private static final Log log = new Log(TCPSynPinger.class); --- NEW FILE: JpcapPinger.java --- package edu.harvard.syrah.pyxida.ping; import java.io.IOException; import java.io.InputStream; import java.net.Inet4Address; import java.net.InetAddress; import java.net.MalformedURLException; import java.util.Arrays; import jpcap.JpcapCaptor; import jpcap.JpcapSender; import jpcap.NetworkInterface; import jpcap.NetworkInterfaceAddress; import jpcap.packet.EthernetPacket; import jpcap.packet.Packet; import edu.harvard.syrah.prp.Log; import edu.harvard.syrah.prp.POut; import edu.harvard.syrah.sbon.async.EventLoop; import edu.harvard.syrah.sbon.async.CallbacksIF.CB0; import edu.harvard.syrah.sbon.comm.AddressFactory; import edu.harvard.syrah.sbon.comm.AddressIF; /** * This is the parent class of the Pingers that use the JPCap library * @author peter * */ abstract class JpcapPinger extends Pinger implements PingerIF { private static final Log log = new Log(JpcapPinger.class); private static final long CAPTION_TIMEOUT = 5000; private static JpcapCaptor captor; private static JpcapSender sender; protected static NetworkInterface device; protected static InetAddress thisIP; protected static byte[] gwMAC; protected static Thread jpcapThread; protected CB0 cbTimeout; class JpcapPingData extends PingData { long sendTS; long recvTS; Packet sendPacket; Packet recvPacket; CB0 cbDone; } protected static JpcapPingData currentPing; public void init(AddressIF defaultPingAddr, final CB0 cbDone) { this.localAddr = AddressFactory.createLocalAddress(); this.defaultPingAddr = defaultPingAddr; // Are we already initialised? if (jpcapThread != null) cbDone.callOK(); jpcapThread = new Thread() { public void run() { NetworkInterface[] devices = JpcapCaptor.getDeviceList(); //log.debug("devices=" + POut.toString(devices)); if (devices.length == 0) log.error("This must be run as root."); nextDevice: for (int i = 0; i <= devices.length; i++) { log.debug("Opening new device " + devices[i].name); try { // TODO The caption timeout is being ignored here, we need a different solution captor = JpcapCaptor.openDevice(devices[i], 2000, false, 5000); } catch (IOException e) { log.debug("Could not open interface no " + i + ". Trying next one"); continue; } device = devices[i]; log.debug("Device " + i + " opened successfully."); if (device.loopback) { log.debug("Ignoring loopback device."); //captor.close(); continue; } for (NetworkInterfaceAddress addr : device.addresses) if (addr.address instanceof Inet4Address) { thisIP = addr.address; log.debug("thisIP=" + thisIP); break; } if (thisIP == null) { log.debug("Local addr not found"); //captor.close(); continue; } // Obtain MAC address of the default gateway InetAddress pingAddr = JpcapPinger.this.defaultPingAddr.getInetAddress(); log.debug("defaultPingAddr=" + pingAddr); captor.setFilter("icmp and dst host " + pingAddr.getHostAddress(), false); InputStream is = null; Packet ping = null; while (true) { // TODO this is ugly -- is there a better way to obtain the MAC address? try { log.debug("Trying to open web connection"); pingAddr.isReachable(1); log.debug("Waiting for packet..."); ping = captor.getPacket(); } catch (MalformedURLException e) { log.error(e.toString()); } catch (IOException e) { log.error(e.toString()); } log.debug("Got one: " + ping); if (ping == null) { log.warn("Cannot obtain MAC address of default gateway."); //captor.close(); continue nextDevice; } else if (Arrays.equals(((EthernetPacket) ping.datalink).dst_mac, device.mac_address)) { log.debug("doing it again"); continue; } gwMAC = ((EthernetPacket) ping.datalink).dst_mac; log.debug("gwMAC=" + POut.toString(gwMAC)); break; } break; } sender = captor.getJpcapSenderInstance(); /* captor.setFilter("icmp and dst host " + thisIP.getHostAddress(), true); sendICMP(ICMPPinger.this.defaultPingAddr); receiveICMP(); */ log.debug("JpcapPinger initalised."); EventLoop.get().registerTimerCB(cbDone); JpcapPinger.this.run(); } }; jpcapThread.start(); } public void shutdown() { shutdown = true; jpcapThread.interrupt(); } protected void addRequest(JpcapPingData pd) { JpcapPinger.currentPing = pd; synchronized(jpcapThread) { jpcapThread.notify(); } } public void run() { try { while (!jpcapThread.isInterrupted()) { if (currentPing == null) { synchronized (jpcapThread) { jpcapThread.wait(); } } if (currentPing != null) { AddressIF pingAddr = currentPing.pingAddr; Packet packet = currentPing.sendPacket; captor.setFilter("icmp and src host " + pingAddr.getHostname(), true); currentPing.sendTS = System.nanoTime() / 1000; try { sender.sendPacket(packet); } catch (Exception e) { log.warn("Failed sending packet: " + e); } log.debug("sendPacket=" + packet); log.debug("sendTS=" + currentPing.sendTS); assert currentPing.sendTS > 0; currentPing.recvPacket = captor.getPacket(); log.debug("Received packet: " + currentPing.recvPacket); EventLoop.get().registerTimerCB(currentPing.cbDone); currentPing = null; } } } catch (InterruptedException e) { /* ignore */ } } } Index: ICMPPinger.java =================================================================== RCS file: /cvsroot/pyxida/Pyxida/src/edu/harvard/syrah/pyxida/ping/ICMPPinger.java,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** ICMPPinger.java 23 Nov 2006 16:46:10 -0000 1.4 --- ICMPPinger.java 23 Nov 2006 23:22:48 -0000 1.5 *************** *** 1,14 **** package edu.harvard.syrah.pyxida.ping; - import java.io.IOException; - import java.io.InputStream; - import java.net.Inet4Address; - import java.net.InetAddress; - import java.net.MalformedURLException; - import java.util.Arrays; - - import jpcap.JpcapCaptor; - import jpcap.NetworkInterface; - import jpcap.NetworkInterfaceAddress; import jpcap.packet.EthernetPacket; import jpcap.packet.ICMPPacket; --- 1,4 ---- *************** *** 17,21 **** import edu.harvard.syrah.prp.ANSI; import edu.harvard.syrah.prp.Log; - import edu.harvard.syrah.prp.POut; import edu.harvard.syrah.sbon.async.CBResult; import edu.harvard.syrah.sbon.async.EventLoop; --- 7,10 ---- *************** *** 25,134 **** import edu.harvard.syrah.sbon.comm.AddressIF; ! class ICMPPinger extends JPCapPinger implements PingerIF { ! private static final Log log = new Log(ICMPPinger.class); private static final long PING_DELAY = 1000; ! ! private AddressIF pingAddr; ! private CB1<Double> cbPing; ! public void init(AddressIF defaultPingAddr, final CB0 cbDone) { ! this.localAddr = AddressFactory.createLocalAddress(); ! this.defaultPingAddr = defaultPingAddr; ! thread = new Thread() { ! public void run() { ! ! NetworkInterface[] devices = JpcapCaptor.getDeviceList(); ! log.debug("devices=" + POut.toString(devices)); ! ! if (devices.length == 0) ! log.error("This must be run as root."); ! ! nextDevice: ! for (int i = 0; i < devices.length; i++) { ! ! log.debug("Opening new device " + devices[i]); ! try { ! captor = JpcapCaptor.openDevice(devices[i], 2000, false, 5000); ! } catch (IOException e) { ! log.debug("Could not open interface no " + i + ". Trying next one"); ! continue; ! } ! ! device = devices[i]; ! log.debug("Device opened successfully."); ! ! if (device.loopback) { ! log.debug("Ignoring loopback device."); ! captor.close(); ! continue; ! } ! ! for (NetworkInterfaceAddress addr : device.addresses) ! if (addr.address instanceof Inet4Address) { ! thisIP = addr.address; ! log.debug("thisIP=" + thisIP); ! break; ! } ! ! if (thisIP == null) { ! log.debug("Local addr not found"); ! captor.close(); ! continue; ! } ! ! // Obtain MAC address of the default gateway ! InetAddress pingAddr = ICMPPinger.this.defaultPingAddr ! .getInetAddress(); ! log.debug("defaultPingAddr=" + pingAddr); ! captor.setFilter("icmp and dst host " + pingAddr.getHostAddress(), ! false); ! InputStream is = null; ! Packet ping = null; ! while (true) { ! // TODO this is ugly -- is there a better way to obtain the MAC address? ! try { ! log.debug("Trying to open web connection"); ! pingAddr.isReachable(1); ! log.debug("Waiting for packet..."); ! ping = captor.getPacket(); ! //captor.setFilter("not", true); ! } catch (MalformedURLException e) { ! log.error(e.toString()); ! } catch (IOException e) { ! log.error(e.toString()); ! } ! log.debug("Got one: " + ping); ! if (ping == null) { ! log.warn("Cannot obtain MAC address of default gateway."); ! captor.close(); ! continue nextDevice; ! } else ! if (Arrays.equals(((EthernetPacket) ping.datalink).dst_mac, ! device.mac_address)) { ! log.debug("doing it again"); ! continue; ! } ! gwMAC = ((EthernetPacket) ping.datalink).dst_mac; ! log.debug("gwMAC=" + POut.toString(gwMAC)); ! break; ! } ! break; ! } ! ! captor.setFilter("icmp and dst host " + thisIP.getHostAddress(), true); ! sender = captor.getJpcapSenderInstance(); ! sendICMP(ICMPPinger.this.defaultPingAddr); ! receiveICMP(); ! ! log.debug("ICMPPinger initalised."); ! ! EventLoop.get().registerTimerCB(cbDone); ! ! ICMPPinger.this.run(); ! } ! }; ! ! thread.start(); } --- 14,24 ---- import edu.harvard.syrah.sbon.comm.AddressIF; ! class ICMPPinger extends JpcapPinger implements PingerIF { ! private static final Log log = new Log(JpcapPinger.class); private static final long PING_DELAY = 1000; ! public void init(AddressIF defaultPingAddr, final CB0 cbDone) { ! super.init(defaultPingAddr, cbDone); } *************** *** 137,141 **** ping(remoteNode, new CB1<Double>() { protected void cb(CBResult result, Double lat) { ! System.out.println("lat=" + lat); EventLoop.get().registerTimerCB(PING_DELAY, new CB0() { protected void cb(CBResult result) { --- 27,31 ---- ping(remoteNode, new CB1<Double>() { protected void cb(CBResult result, Double lat) { ! System.out.println("lat=" + (lat > 0 ? lat : "Timeout")); EventLoop.get().registerTimerCB(PING_DELAY, new CB0() { protected void cb(CBResult result) { *************** *** 147,156 **** } ! public void ping(AddressIF remoteNode, CB1<Double> cbPing) throws UnsupportedOperationException { ! this.pingAddr = remoteNode; ! this.cbPing = cbPing; ! synchronized(thread) { ! thread.notify(); ! } } --- 37,55 ---- } ! public void ping(AddressIF remoteNode, final CB1<Double> cbPing) throws UnsupportedOperationException { ! final JpcapPingData pd = new JpcapPingData(); ! pd.pingAddr = remoteNode; ! pd.cbLat = cbPing; ! pd.sendPacket = createICMP(remoteNode); ! pd.cbDone = new CB0() { ! protected void cb(CBResult resultOK) { ! pd.recvTS = parseICMP(pd.recvPacket); ! long lat = 0; ! if (pd.recvTS > 0) ! lat = pd.recvTS - pd.sendTS; ! cbPing.call(resultOK, lat / 1000.0); ! } ! }; ! addRequest(pd); } *************** *** 159,167 **** throw new UnsupportedOperationException(); } ! ! private long sendICMP(AddressIF addr) { assert device != null; ! log.debug("Sending ICMP ping to " + addr); ICMPPacket icmp = new ICMPPacket(); --- 58,66 ---- throw new UnsupportedOperationException(); } ! ! private ICMPPacket createICMP(AddressIF addr) { assert device != null; ! log.debug("Creating ICMP ping to " + addr); ICMPPacket icmp = new ICMPPacket(); *************** *** 179,249 **** icmp.datalink = ether; ! long sendTS = System.nanoTime() / 1000; ! try { ! sender.sendPacket(icmp); ! } catch (Exception e) { ! log.warn("Failed sending packet: " + e); ! } ! log.debug("sendPacket=" + icmp); ! return sendTS; } ! ! private long receiveICMP() { ! long recvTS = -1; ! ICMPPacket p = (ICMPPacket) captor.getPacket(); ! log.debug("Received ICMP packet: " + p); ! if (p == null) { log.debug("Timeout"); ! } else if (p.type == ICMPPacket.ICMP_TIMXCEED) { ! p.src_ip.getHostName(); ! log.debug("ICMP_TIMXCEED: " + p.src_ip.toString()); ! } else if (p.type == ICMPPacket.ICMP_UNREACH) { ! p.src_ip.getHostName(); ! log.debug("ICMP_UNREACH: " + p.src_ip.toString()); ! } else if (p.type == ICMPPacket.ICMP_ECHOREPLY) { ! p.src_ip.getHostName(); ! long sec = p.sec; ! long usec = p.usec; ! log.debug("ICMP_ECHOREPLY: " + p.src_ip + " sec=" + sec + " usec=" + usec); ! recvTS = (sec * 1000 * 1000) + usec; ! log.debug("recvTS=" + recvTS); } ! log.debug("Finished receiveICMP"); return recvTS; } - public void run() { - try { - while (!thread.isInterrupted()) { - - synchronized (thread) { - thread.wait(); - } - - if (pingAddr != null) { - captor.setFilter("icmp and src host " + pingAddr.getHostname(), true); - long sendTS = sendICMP(pingAddr); - log.debug("sendTS=" + sendTS); - assert sendTS > 0; - long recvTS = receiveICMP(); - assert recvTS > 0; - final long lat = recvTS - sendTS; - pingAddr = null; - EventLoop.get().registerTimerCB(new CB0() { - protected void cb(CBResult resultOK) { - cbPing.call(resultOK, (double) lat / 1000.0); - } - }); - } - } - } catch (InterruptedException e) { /* ignore */ } - } - - public void shutdown() { - shutdown = true; - thread.interrupt(); - } - public static void main(final String[] args) { ANSI.use(true); --- 78,111 ---- icmp.datalink = ether; ! return icmp; } ! ! private long parseICMP(Packet p) { ! long recvTS = Long.MIN_VALUE; ! ICMPPacket icmp = (ICMPPacket) p; ! if (icmp == null) { log.debug("Timeout"); ! } else ! if (icmp.type == ICMPPacket.ICMP_TIMXCEED) { ! icmp.src_ip.getHostName(); ! log.debug("ICMP_TIMXCEED: " + icmp.src_ip.toString()); ! } else ! if (icmp.type == ICMPPacket.ICMP_UNREACH) { ! icmp.src_ip.getHostName(); ! log.debug("ICMP_UNREACH: " + icmp.src_ip.toString()); ! } else ! if (icmp.type == ICMPPacket.ICMP_ECHOREPLY) { ! icmp.src_ip.getHostName(); ! long sec = p.sec; ! long usec = p.usec; ! log.debug("ICMP_ECHOREPLY: " + icmp.src_ip + " sec=" + sec + " usec=" + usec); ! recvTS = (sec * 1000 * 1000) + usec; ! log.debug("recvTS=" + recvTS); } ! log.debug("Finished parseICMP"); return recvTS; } public static void main(final String[] args) { ANSI.use(true); *************** *** 258,262 **** final PingerIF pinger = new ICMPPinger(); ! EventLoop.get().registerTimerCB(new CB0() { protected void cb(CBResult resultOK) { --- 120,124 ---- final PingerIF pinger = new ICMPPinger(); ! EventLoop.get().registerTimerCB(new CB0() { protected void cb(CBResult resultOK) { *************** *** 264,268 **** protected void cb(CBResult result, AddressIF defaultAddr) { switch (result.state) { ! case OK: { pinger.init(defaultAddr, new CB0() { protected void cb(CBResult arg0) { --- 126,130 ---- protected void cb(CBResult result, AddressIF defaultAddr) { switch (result.state) { ! case OK: { pinger.init(defaultAddr, new CB0() { protected void cb(CBResult arg0) { *************** *** 271,275 **** switch (result.state) { case OK: { ! System.out.println("Pinging addr=" + addr + " "); pinger.testPing(addr); break; --- 133,137 ---- switch (result.state) { case OK: { ! System.out.println("Pinging addr=" + addr + " using ICMP"); pinger.testPing(addr); break; |