// This software has been placed in the public domain by its author // A node's low-level network interface package sim; import java.util.LinkedList; class NetworkInterface implements EventTarget { public final static boolean LOG = false; public final int address; // Represents an IP address and port private Node node; // The owner of this network interface private double txSpeed, rxSpeed; // Bytes per second private LinkedList txQueue; // Queue of outgoing packets private LinkedList rxQueue; // Queue of incoming packets private int txQueueSize, rxQueueSize; // Number of bytes in each queue private int txQueueMaxSize, rxQueueMaxSize; // Drop-tail queues public NetworkInterface (Node node, double txSpeed, double rxSpeed) { this.node = node; this.txSpeed = txSpeed; this.rxSpeed = rxSpeed; txQueue = new LinkedList(); rxQueue = new LinkedList(); txQueueSize = rxQueueSize = 0; // Bytes currently queued txQueueMaxSize = 10000; rxQueueMaxSize = 20000; // Attach the interface to the network address = Network.register (this); } // Called by Node public void sendPacket (Packet p) { if (txQueueSize + p.size > txQueueMaxSize) { if (LOG) log ("no room in txQueue, " + p + " lost"); return; } txQueue.add (p); txQueueSize += p.size; if (LOG) log (txQueueSize + " bytes in txQueue"); // If there are no other packets in the queue, start to transmit if (txQueue.size() == 1) txStart (p); } // Event callbacks // Add a packet to the rx queue private void rxQueueAdd (Packet p) { if (rxQueueSize + p.size > rxQueueMaxSize) { if (LOG) log ("no room in rxQueue, " + p + " lost"); return; } rxQueue.add (p); rxQueueSize += p.size; if (LOG) log (rxQueueSize + " bytes in rxQueue"); // If there are no other packets in the queue, start to receive if (rxQueue.size() == 1) rxStart (p); } // Start receiving a packet private void rxStart (Packet p) { if (LOG) log ("starting to receive " + p); // Delay depends on rx speed Event.schedule (this, p.size / rxSpeed, RX_END, p); } // Finish receiving a packet, pass it to the node private void rxEnd (Packet p) { if (LOG) log ("finished receiving " + p); node.handlePacket (p); rxQueueSize -= p.size; rxQueue.poll(); // If there's another packet waiting, start to receive it if (!rxQueue.isEmpty()) rxStart (rxQueue.peek()); } // Start transmitting a packet private void txStart (Packet p) { if (LOG) log ("starting to transmit " + p); // Delay depends on tx speed Event.schedule (this, p.size / txSpeed, TX_END, p); } // Finish transmitting a packet private void txEnd (Packet p) { if (LOG) log ("finished transmitting " + p); Network.deliver (p); txQueueSize -= p.size; txQueue.poll(); // If there's another packet waiting, start to transmit it if (!txQueue.isEmpty()) txStart (txQueue.peek()); } private void log (String message) { Event.log (address + " " + message); } // EventTarget interface public void handleEvent (int code, Object data) { if (code == RX_QUEUE) rxQueueAdd ((Packet) data); else if (code == RX_END) rxEnd ((Packet) data); else if (code == TX_END) txEnd ((Packet) data); } public final static int RX_QUEUE = Event.code(); private final static int RX_END = Event.code(); private final static int TX_END = Event.code(); }