//----------------------------------------------------------------- // CSE 461 Project 1 // // inet.java: a simulated internet link with drops and reordering // See simulate.java for a description of the interfaces //----------------------------------------------------------------- import java.io.*; import java.util.*; class InternetLink implements Link, TimerClient { // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // InternetLink constructor: // // timer the timer to operate with // // mtu the max transmission unit, in bytes // // bandwidthMean average bandwidth, in Mbits/sec // bandwidthSD standard deviation, in Mbits/sec // bandwidthWalk 0.0 -> stable around mean, // 1.0 -> mean walks with previous value // latencyMean average latency, in milliseconds // latencySD standard deviation, in milliseconds // latencyWalk like bandwidthWalk // // dropProb probability that a packet is dropped // // seed seed for the random number generator // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - public InternetLink (Timer timer, int mtu, double bandwidthMean, double bandwidthSD, double bandwidthWalk, double latencyMean, double latencySD, double latencyWalk, double dropProb, long seed) { this.timer = timer; this.mtu = mtu; this.bandwidthMean = bandwidthMean / 8.0; this.bandwidthSD = bandwidthSD / 8.0; this.bandwidthWalk = bandwidthWalk; bandwidthLast = bandwidthMean; this.latencyMean = latencyMean; this.latencySD = latencySD; this.latencyWalk = latencyWalk; latencyLast = latencyMean; this.dropProb = dropProb; rand = new Random (seed); addrToHost = new Hashtable (); hostToAddr = new Hashtable (); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Tell the link about a receier. This maps the address to // that receiver. Clients need to do this (either directly // or through the NetworkInterface class) in order to receive // packets. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - public synchronized void AddReceiver (PacketReceiver rcvr, Address address) { addrToHost.put (address, rcvr); hostToAddr.put (rcvr, address); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Remove a receiver that was added with AddReceiver // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - public synchronized void RemoveReceiver (PacketReceiver rcvr) { Address address = (Address) hostToAddr.get (rcvr); if (address != null) addrToHost.remove (address); hostToAddr.remove (rcvr); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Get the Maximum Transmission Unit, in bytes of data // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - public int MTU () { return mtu; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Transmit a packet on the link. This will block the caller // until the packet has been completely put on the link // (the bandwidth delay). The arrival is scheduled for some // time in the future. // // This correctly handles waiting for the timer. Threads which // call this need to be registered with the timer. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - public void TransmitPacket (Packet p) { if (p.data.length > MTU ()) return; synchronized (this) { bandwidthLast = Distribution (bandwidthMean, bandwidthSD, bandwidthWalk, bandwidthLast); latencyLast = Distribution (latencyMean, latencySD, latencyWalk, latencyLast); } double transmitTime = p.data.length / bandwidthLast; // in us double arrivalTime = latencyLast * 1000; // in us Debug.println ('n', "Computed times for packet from " + p.sourceAddr); try { timer.WaitFor ((long) transmitTime, Timer.US); } catch (NotActiveThreadException e) { System.out.println ("BAD: not active thread in inet.java"); System.exit (1); } Debug.println ('n', "Cleared xmit for packet from " + p.sourceAddr); if (rand.nextDouble () > dropProb) { timer.SetTimeout (this, (long) arrivalTime, Timer.US, p); Debug.println ('p', "Packet xmit: " + p.sourceAddr + " -> " + p.destinationAddr + " (" + (p.ack ? "A" : "D") + p.sequenceNum + ")" + " sent @" + (long)(timer.CurrentSimTime () - transmitTime) + " clrd @" + (long)(timer.CurrentSimTime () + 0) + " arrv @" + (long)(timer.CurrentSimTime () + arrivalTime)); } else { Debug.println ('p', "Packet xmit: " + p.sourceAddr + " -> " + p.destinationAddr + " (" + (p.ack ? "A" : "D") + p.sequenceNum + ")" + " sent @" + (long)(timer.CurrentSimTime () - transmitTime) + " clrd @" + (long)(timer.CurrentSimTime () + 0) + " DROPPED"); } Debug.println ('n', "Set arrival for packet from " + p.sourceAddr); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Given the parameters, sample a random variable // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - private double Distribution (double mean, double sd, double walk, double last) { double target = walk * last + (1.0 - walk) * mean; double retval = rand.nextGaussian () * sd + target; if (retval < 0.0) retval = 0.0; return retval; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Timeout is used as the packet arrival mechanism. The info // should be the Packet that is arriving // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - public void Timeout (Object info) { Packet p = (Packet) info; PacketReceiver rcvr = null; synchronized (this) { rcvr = (PacketReceiver) addrToHost.get (p.destinationAddr); } if (rcvr != null) rcvr.PacketArrived (p); else Debug.println ('n', "Dropping packet for unknown addr " + p.destinationAddr); } private Timer timer; private double bandwidthMean; private double bandwidthSD; private double bandwidthWalk; private double bandwidthLast; private double latencyMean; private double latencySD; private double latencyWalk; private double latencyLast; private double dropProb; private Random rand; private Hashtable addrToHost; private Hashtable hostToAddr; private int mtu; }