/*
** This file is part of Filius, a network construction and simulation software.
**
** Originally created at the University of Siegen, Institute "Didactics of
** Informatics and E-Learning" by a students' project group:
** members (2006-2007):
** André Asschoff, Johannes Bade, Carsten Dittich, Thomas Gerding,
** Nadja Haßler, Ernst Johannes Klebert, Michell Weyer
** supervisors:
** Stefan Freischlad (maintainer until 2009), Peer Stechert
** Project is maintained since 2010 by Christian Eibl <filius@c.fameibl.de>
** and Stefan Freischlad
** Filius is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) version 3.
**
** Filius is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied
** warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
** PURPOSE. See the GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Filius. If not, see <http://www.gnu.org/licenses/>.
*/
package filius.software.vermittlungsschicht;
import java.util.LinkedList;
import java.util.ListIterator;
import filius.Main;
import filius.exception.VerbindungsException;
import filius.hardware.NetzwerkInterface;
import filius.hardware.knoten.InternetKnoten;
import filius.software.ProtokollThread;
import filius.software.netzzugangsschicht.EthernetFrame;
import filius.software.system.InternetKnotenBetriebssystem;
import filius.hardware.Verbindung;
/**
* Klasse zur Ueberwachung des Puffers fuer eingehende ARP-Pakete
*
*/
public class ICMPThread extends ProtokollThread {
private ICMP vermittlung;
/** der von dem Thread zu ueberwachende Puffer */
private LinkedList<IcmpPaket> rcvdPackets;
public ICMPThread(ICMP vermittlung) {
super(((InternetKnotenBetriebssystem) vermittlung.holeSystemSoftware())
.holeEthernet().holeICMPPuffer()); // zu überwachender Puffer als Parameter nötig für Thread-Steuerung
Main.debug.println("INVOKED-2 ("+this.hashCode()+", T"+this.getId()+") "+getClass()+" (ICMPThread), constr: ICMPThread("+vermittlung+")");
this.rcvdPackets = new LinkedList<IcmpPaket>();
this.vermittlung = vermittlung;
}
/**
* Hilfsmethode zur Bestimmung der Netzwerkkarte, die im Rechnernetz ist,
* aus der das ICMP-Paket kam.
*
* @param paket
* ein eingegangenes ICMP-Paket
* @return die Netzwerkkarte aus dem Rechnernetz, aus dem das ICMP-Paket
* verschickt wurde
*/
private NetzwerkInterface bestimmeNetzwerkInterface(IcmpPaket paket) {
Main.debug.println("INVOKED ("+this.hashCode()+", T"+this.getId()+") "+getClass()+" (ICMPThread), bestimmeNetzwerkInterface("+paket.toString()+")");
NetzwerkInterface nic = null;
ListIterator it;
it = ((InternetKnoten) vermittlung.holeSystemSoftware().getKnoten())
.getNetzwerkInterfaces().listIterator();
while (it.hasNext()) {
nic = (NetzwerkInterface) it.next();
if (VermittlungsProtokoll.gleichesRechnernetz(paket.getQuellIp(),
nic.getIp(), nic.getSubnetzMaske())) {
return nic;
}
}
return nic;
}
/**
* Methode zur Verarbeitung eingehender ICMP-Pakete <br />
*/
protected void verarbeiteDatenEinheit(Object datenEinheit) {
IcmpPaket icmpPaket = (IcmpPaket) datenEinheit;
// TTL dekrementieren
icmpPaket.setTtl(icmpPaket.getTtl()-1);
if (vermittlung.isLocal(icmpPaket.getZielIp())) {
// Paket wurde an diesen Rechner gesendet
if (icmpPaket.getIcmpType() == 8
&& icmpPaket.getIcmpCode() == 0) {
vermittlung.sendEchoReply(icmpPaket);
} else {
synchronized(rcvdPackets) {
rcvdPackets.add(icmpPaket);
rcvdPackets.notify();
}
}
} else {
// Paket wurde an anderen Rechner gesendet und
// muss weitergeleitet werden
vermittlung.weiterleitenPaket(icmpPaket);
}
}
// method to actually send a ping and compute the pong event
// return true if successful
public int startSinglePing(String destIp, int seqNr) throws java.util.concurrent.TimeoutException {
Main.debug.println("INVOKED ("+this.hashCode()+", T"+this.getId()+") "+getClass()+" (ICMPThread), startSinglePing("+destIp+","+seqNr+")");
int resultTTL=-20; // return ttl field of received echo reply packet
vermittlung.sendEchoRequest(destIp, seqNr);
synchronized(rcvdPackets) {
try {
rcvdPackets.wait(Verbindung.holeRTT());
}
catch (InterruptedException e) {
}
if(rcvdPackets.size()==0) {
Main.debug.println("DEBUG ("+this.hashCode()+", T"+this.getId()+") "+getClass()+" (ICMPThread), startSinglePing, NO reply in queue");
throw new java.util.concurrent.TimeoutException("Destination Host Unreachable"); // not absolutely correct, but who cares...
}
else {
Main.debug.println("DEBUG ("+this.hashCode()+", T"+this.getId()+") "+getClass()+" (ICMPThread), startSinglePing, reply in queue");
IcmpPaket rcvdIcmpPaket = rcvdPackets.removeFirst();
if (rcvdIcmpPaket != null && !(destIp.equals(rcvdIcmpPaket.getQuellIp())
&& seqNr == rcvdIcmpPaket.getSeqNr() && rcvdIcmpPaket.getIcmpType() == 0)) {
throw new java.util.concurrent.TimeoutException("Destination Host Unreachable"); // not absolutely correct, but who cares...
}
resultTTL = rcvdIcmpPaket.getTtl();
}
}
Main.debug.println("INVOKED ("+this.hashCode()+", T"+this.getId()+") "+getClass()+" (ICMPThread), startSinglePing, return "+resultTTL);
return resultTTL;
}
public IcmpPaket sendProbe(String destIp, int ttl, int seqNr) {
vermittlung.sendeICMP(8, 0, ttl, seqNr, destIp);
synchronized(rcvdPackets) {
try {
rcvdPackets.wait(Verbindung.holeRTT());
} catch (InterruptedException e) {
}
if (rcvdPackets.size() > 0) {
return rcvdPackets.removeFirst();
}
}
return null;
}
}