/* ** 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.dateiaustausch; import java.util.LinkedList; import java.util.ListIterator; import filius.Main; import filius.software.Anwendung; /** * In dieser Klasse werden Anfragen an andere Teilnehmer im * Peer-To-Peer-Netzwerk verschickt bzw. weitergeleitet und dafuer gesorgt, dass * die dazu gehoerigen eingehenden Antworten verarbeitet werden. Dazu wird ein * neuer Thread mit einem PeerToPeerClientMitarbeiter gestartet. * */ class PeerToPeerClient extends Anwendung { /** * Die zugehoerige PeerToPeerAnwendung, die diesen Client zur Verarbeitung * von eigenen Anfragen verwendet. */ private PeerToPeerAnwendung peerToPeerAnwendung; /** * Eine Liste mit allen Mitarbeiter-Threads, die zur Verarbeitung der * Antworten auf eigene Anfragen verwendet werden. */ private LinkedList<PeerToPeerClientMitarbeiter> mitarbeiterEigeneAnfragen = new LinkedList<PeerToPeerClientMitarbeiter>(); /** * Eine Liste mit allen Mitarbeiter-Threads, die zur Verarbeitung von * Antworten auf fremde, d. h. weitergeleitete, Anfragen verwendet werden. */ private LinkedList<PeerToPeerClientMitarbeiter> mitarbeiterFremdeAnfragen = new LinkedList<PeerToPeerClientMitarbeiter>(); /** * Konstruktor, in dem die zugehoerige PeerToPeerAnwendung initialisiert und * der Konstruktor der Oberklasse aufgerufen wird. * * @param peerToPeerAnwendung */ PeerToPeerClient(PeerToPeerAnwendung peerToPeerAnwendung) { super(); Main.debug.println("INVOKED-2 ("+this.hashCode()+", T"+this.getId()+") "+getClass()+" (PeerToPeerClient), constr: PeerToPeerClient("+peerToPeerAnwendung+")"); this.peerToPeerAnwendung = peerToPeerAnwendung; } /** Zum beenden der Threads, die durch diesen Client gestartet wurden. */ public void beenden() { Main.debug.println("INVOKED ("+this.hashCode()+", T"+this.getId()+") "+getClass()+" (PeerToPeerClient), beenden()"); ListIterator<?> it; PeerToPeerClientMitarbeiter m; super.beenden(); it = mitarbeiterEigeneAnfragen.listIterator(); while (it.hasNext()) { m = (PeerToPeerClientMitarbeiter) it.next(); m.beenden(); } it = mitarbeiterFremdeAnfragen.listIterator(); while (it.hasNext()) { m = (PeerToPeerClientMitarbeiter) it.next(); m.beenden(); } } /** * Verschicken eines eigenden oder weitersenden einer fremden * Ping-Nachricht. Wenn eine IP-Adresse angegeben wird, zu dem diese * Nachricht verschickt werden soll, wird die Ping-Nachricht als eigene * Anfrage behandelt. Eine Ping-Nachricht wird zum Beitreten zu einem * Peer-To-Peer-Netzwerk verschickt. * * @param wohinZuerst * die IP-Adresse des Servents, mit welchem man sich zuerst * verbinden moechte * @param pingPaket * das Ping-Paket, welches verschickt wird * @param peerToPeerServerMitarbeiter * der peerToPeerServerMitarbeiter, ueber den eine moegliche * Antwort zurueck geschickt wird * @param nichtIP * die IP, an die das Paket nicht weitergeleitet werden darf * (weil es daher kommt) */ void sendePing(String wohinZuerst, PingPaket pingPaket, String nichtIP) { Main.debug.println("INVOKED ("+this.hashCode()+", T"+this.getId()+") "+getClass()+" (PeerToPeerClient), sendePing("+wohinZuerst+","+pingPaket+","+nichtIP+")"); // der erste Schritt => nur an den senden, den man angegeben hat, der // kuemmert sich um das weitere fluten if (!wohinZuerst.equals("")) { PeerToPeerClientMitarbeiter lauscher = new PeerToPeerClientMitarbeiter( peerToPeerAnwendung, wohinZuerst, pingPaket); mitarbeiterEigeneAnfragen.add(lauscher); lauscher.start(); } // Ping weiter fluten (an alle, die in der Liste stehen, ausser an den, // von dem es aktuell kam und // den, wo es urspruenglich her kam else { for (int i = 0; i < peerToPeerAnwendung .holeBekanntePeerToPeerTeilnehmer().size(); i++) { String aktuelle = (String) peerToPeerAnwendung .holeBekanntePeerToPeerTeilnehmer().get(i); if (aktuelle.equals(nichtIP) == false && aktuelle.equals(pingPaket.getIp()) == false) { PeerToPeerClientMitarbeiter lauscher = new PeerToPeerClientMitarbeiter( peerToPeerAnwendung, aktuelle, pingPaket); mitarbeiterFremdeAnfragen.add(lauscher); lauscher.start(); } } } } /** * Damit wird eine initiierte Suchanfrage abgebrochen. D. h., dass alle * Threads, die auf eingehende Antworten auf eine Suchanfrage warten, * beendet werden. */ void abbrechenSuche() { Main.debug.println("INVOKED ("+this.hashCode()+", T"+this.getId()+") "+getClass()+" (PeerToPeerClient), abbrechenSuche()"); ListIterator<?> it; PeerToPeerClientMitarbeiter mitarbeiter; it = mitarbeiterEigeneAnfragen.listIterator(); while (it.hasNext()) { mitarbeiter = (PeerToPeerClientMitarbeiter) it.next(); mitarbeiter.beenden(); } } /** * erstellt eine HTTP Nachricht und schickt sie an den Teilnehmer, auf * welchem die entsprechende Datei liegt. Auch dazu wird ein * Mitarbeiter-Thread gestartet und dieser in die Liste der Threads fuer * eigene Anfragen eingefuegt. * * @param teilnehmerIp * der Teilnehmer, auf welchem die Datei liegt * @param dateiName * der Name der gesuchten Datei */ void dateiVomTeilnehmerAnfordern(String teilnehmerIp, String dateiName) { Main.debug.println("INVOKED ("+this.hashCode()+", T"+this.getId()+") "+getClass()+" (PeerToPeerClient), dateiVomTeilnehmerAnfordern("+teilnehmerIp+","+dateiName+")"); PeerToPeerClientMitarbeiter m; m = new PeerToPeerClientMitarbeiter(peerToPeerAnwendung, teilnehmerIp, dateiName); m.start(); mitarbeiterEigeneAnfragen.add(m); } /** * Initiierung und weiterleitung einer Suchanfrage (Query). Zur weiteren * Verarbeitung wird ein neuer Mitarbeiter-Thread erzeugt. Der Thread wird * der Liste fuer eigene Anfragen hinzugefuegt, wenn die GUID in der Liste * der eigenen Anfragen der PeerToPeerAnwendung vorhanden ist. Die Anfrage * wird immer an alle bekannten Teilnehmer im Peer-To-Peer-Netzwerk * verschickt. * * @param anfragePaket * das weiterzusendende Paket * @param absenderIP * die IP-Adresse des Absenders * @param peerToPeerServerMitarbeiter * der PeerToPeerServermitarbeiter, an den moegliche Antworten * zurueck uebergeben werden muessen */ void sendeAnfrage(QueryPaket anfragePaket, String absenderIP) { Main.debug.println("INVOKED ("+this.hashCode()+", T"+this.getId()+") "+getClass()+" (PeerToPeerClient), sendeAnfrage("+anfragePaket+","+absenderIP+")"); LinkedList<String> dieNachbarn; PeerToPeerClientMitarbeiter lauscher; String nachbar; dieNachbarn = peerToPeerAnwendung.holeBekanntePeerToPeerTeilnehmer(); /* Anfrage an ALLE direkten Nachbarn */ for (int i = 0; i < dieNachbarn.size(); i++) { nachbar = (String) dieNachbarn.get(i); if (!nachbar.equals(absenderIP)) { lauscher = new PeerToPeerClientMitarbeiter( peerToPeerAnwendung, nachbar, anfragePaket); if (peerToPeerAnwendung.holeEigeneAnfragen().contains( anfragePaket.getGuid())) { mitarbeiterEigeneAnfragen.add(lauscher); } else { mitarbeiterFremdeAnfragen.add(lauscher); } lauscher.start(); } } } }