/* ** 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.transportschicht; import java.lang.Thread.State; import java.util.Hashtable; import java.util.LinkedList; import java.util.Random; import filius.Main; import filius.exception.SocketException; import filius.exception.VerbindungsException; import filius.rahmenprogramm.I18n; import filius.software.Protokoll; import filius.software.system.InternetKnotenBetriebssystem; public abstract class TransportProtokoll extends Protokoll implements I18n, Runnable { private static final int PORT_UNTERE_GRENZE = 1024; private static final int PORT_OBERE_GRENZE = 65535; protected static final int TTL = 64; private int typ; /** IP-Adresse und Segment, das in einem neuen Thread verschickt wird */ private LinkedList<Object[]> segmentListe = new LinkedList<Object[]>(); private Hashtable<Integer, SocketSchnittstelle> portTabelle; private TransportProtokollThread thread; /** * Dieser Thread fuehrt die run()-Methode dieser Klasse aus und wird dazu * verwendet, Segmente zu verschicken. */ private Thread sendeThread = null; /** * In diesem Attribut wird gespeichert, ob der Thread zum Versenden von * Segmenten laeuft. */ private boolean running = false; /** * @author carsten * @param betriebssystem */ public TransportProtokoll(InternetKnotenBetriebssystem betriebssystem, int typ) { super(betriebssystem); Main.debug.println("INVOKED-2 ("+this.hashCode()+") "+getClass()+" (TransportProtokoll), constr: TransportProtokoll("+betriebssystem+","+typ+")"); this.typ = typ; portTabelle = new Hashtable<Integer, SocketSchnittstelle>(); } public Hashtable<Integer, SocketSchnittstelle> holeAktiveSockets() { return this.portTabelle; } public int holeTyp() { return typ; } public int reserviereFreienPort(Socket socket) { Main.debug.println("INVOKED ("+this.hashCode()+") "+getClass()+" (TransportProtokoll), reserviereFreienPort("+socket+")"); // Freien Port suchen boolean portGefunden = false; int freienPort; do { freienPort = sucheFreienPort(); if (!portTabelle.containsKey(freienPort)) { portGefunden = true; } } while (!portGefunden); reservierePort(freienPort, socket); return freienPort; } public SocketSchnittstelle holeSocket(int port) throws SocketException { Main.debug.println("INVOKED ("+this.hashCode()+") "+getClass()+" (TransportProtokoll), holeSocket("+port+")"); if (port == -1 ) { throw new SocketException(messages.getString("sw_transportprotokoll_msg3")); } if (!portTabelle.containsKey(port)) throw new SocketException(messages .getString("sw_transportprotokoll_msg1") + " " + port + " " + messages.getString("sw_transportprotokoll_msg2")); return (SocketSchnittstelle) portTabelle.get(port); } public boolean isUsed(int port) { return portTabelle.containsKey(port); } private int sucheFreienPort() { Main.debug.println("INVOKED ("+this.hashCode()+") "+getClass()+" (TransportProtokoll), sucheFreienPort()"); int spanne = PORT_OBERE_GRENZE - PORT_UNTERE_GRENZE; Random random = new Random(); int zufallsZahl = Math.abs(random.nextInt()); int zahl = (zufallsZahl) % spanne; return (PORT_UNTERE_GRENZE + zahl); } public boolean reservierePort(int port, SocketSchnittstelle socket) { Main.debug.println("INVOKED ("+this.hashCode()+") "+getClass()+" (TransportProtokoll), reservierePort("+port+","+socket+")"); if (portTabelle.containsKey(port)) { Main.debug.println("ERROR ("+this.hashCode()+"): Port "+port+" ist bereits belegt!"); return false; } else { portTabelle.put(port, socket); return true; } } public boolean gibPortFrei(int port) { Main.debug.println("INVOKED ("+this.hashCode()+") "+getClass()+" (TransportProtokoll), gibPortFrei("+port+")"); if (portTabelle.containsKey(port)) { portTabelle.remove(port); return true; } else { return false; } } /** * @param zielIp - * Ip des Empfaengers * @param protokoll - * Protokollnummer des Protokolls, auf dass aufgesetzt wird. * @param segment - * Segment mit Daten zur IP-Schicht */ protected void senden(String zielIp, Object segment) { senden(zielIp, null, segment); } protected void senden(String zielIp, String quellIp, Object segment) { Main.debug.println("INVOKED ("+this.hashCode()+") "+getClass()+" (TransportProtokoll), senden("+zielIp+","+segment+")"); // Main.debug.println(getClass().toString() // + "\n\tsenden() wurde aufgerufen" + "\n\tZiel-Adresse: " // + zielIp + ":" + ((Segment) segment).getZielPort() // + "\n\tDaten: " + ((Segment) segment).getDaten()); synchronized (segmentListe) { segmentListe.addLast((new Object[] { zielIp, quellIp, segment })); segmentListe.notifyAll(); } } public void run() { Main.debug.println("INVOKED ("+this.hashCode()+") "+getClass()+" (TransportProtokoll), run()"); InternetKnotenBetriebssystem bs; Object[] temp; while (running) { synchronized (segmentListe) { if (segmentListe.size() < 1) { try { segmentListe.wait(); } catch (InterruptedException e1) { } } if (segmentListe.size() > 0) { temp = (Object[]) segmentListe.removeFirst(); bs = (InternetKnotenBetriebssystem) holeSystemSoftware(); bs.holeIP().senden((String) temp[0], (String) temp[1], holeTyp(), TTL, temp[2]); } } } } public void starten() { Main.debug.println("INVOKED ("+this.hashCode()+") "+getClass()+" (TransportProtokoll), starten()"); portTabelle = new Hashtable<Integer, SocketSchnittstelle>(); thread = new TransportProtokollThread(this); thread.starten(); if (!running) { running = true; if (sendeThread != null && (sendeThread.getState().equals(State.WAITING) || sendeThread .getState().equals(State.BLOCKED))) { } else { sendeThread = new Thread(this); sendeThread.start(); } } } public void beenden() { Main.debug.println("INVOKED ("+this.hashCode()+") "+getClass()+" (TransportProtokoll), beenden()"); thread.beenden(); running = false; if (sendeThread != null && (sendeThread.getState().equals(State.WAITING) || sendeThread .getState().equals(State.BLOCKED))) { sendeThread.interrupt(); } } }