/* ** 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 filius.Main; import filius.exception.SocketException; import filius.exception.TimeOutException; import filius.exception.VerbindungsException; import filius.rahmenprogramm.I18n; import filius.software.system.InternetKnotenBetriebssystem; import filius.software.vermittlungsschicht.IP; import filius.software.vermittlungsschicht.IpPaket; /** * Dieser Klasse ist Oberklasse von UDPSocket und TCPSocket. Da die * Funktionalitaet nicht als eigener Thread implementiert ist, kann immer nur * entweder gesendet oder empfangen werden! * */ public abstract class Socket implements SocketSchnittstelle, I18n { /** * Konstanten zur Spezifizierung des Modus des Sockets */ protected static final int AKTIV = 1, PASSIV = 2; /** * Ob der Socket im Passiv- oder Aktiv-Modus betrieben wird. AKTIV bedeutet, * dass der Verbindungsaufbau zu einem anderen Socket initiiert wird, PASSIV * bedeutet, dass der Socket auf eingehende Verbindungsanfragen wartet. * Dieses Attribut sollte also mit einer der Konstanten AKTIV / PASSIV * initialisiert werden! */ protected int modus; /** Das mit dem Socket verbundene Transport-Protokoll */ protected TransportProtokoll protokoll; /** der lokal belegte Port */ protected int lokalerPort = -1; protected String quellIp; /** * die IP-Adresse des Knotens, auf dem der entfernte Socket bereitgestellt * wird */ protected String zielIp; /** TCP-/UDP-Port auf dem entfernten Rechner */ protected int zielPort; /** * Konstruktor zur Initialisierung eines Client-Sockets. Dazu wird das mit * dem Socket verbundene Transport-Protokoll initialisiert. <br /> * Der Konstruktor ist <b> nicht blockierend</b>. * * @param betriebssystem * @param zielAdresse * @param zielPort * @throws VerbindungsException */ public Socket(InternetKnotenBetriebssystem betriebssystem, String zielAdresse, int zielPort, int transportProtokoll) throws VerbindungsException { Main.debug.println("INVOKED ("+this.hashCode()+") "+getClass()+" (Socket), constr: Socket("+betriebssystem+","+zielAdresse+","+zielPort+","+transportProtokoll+")"); String ip; modus = AKTIV; if (transportProtokoll == IpPaket.TCP) protokoll = betriebssystem.holeTcp(); else protokoll = betriebssystem.holeUdp(); ip = ipCheck(zielAdresse); if (ip != null) { this.zielIp = ip; } else { this.zielIp = betriebssystem.holeDNSClient().holeIPAdresse(zielAdresse); } if (zielIp != null) { this.zielPort = zielPort; } else { throw new VerbindungsException(messages.getString("sw_socket_msg1")); } } /** * Konstruktor zur Initialisierung eines Client-Sockets. Dazu wird der * Konstruktor verwendet, der keinen lokalen Port uebergeben bekommt. <br /> * Der Konstruktor ist <b> nicht blockierend</b>. * * @param betriebssystem * @param zielAdresse * @param zielPort * @param lokalerPort * ein bestimmter lokaler Port, der beim Betriebssystem * reserviert werden soll. Dieser Parameter wird nur dann * verwendet, wenn der Wert groesser 0 ist. * @throws VerbindungsException */ public Socket(InternetKnotenBetriebssystem betriebssystem, String zielAdresse, int zielPort, int transportProtokoll, int lokalerPort) throws VerbindungsException { this(betriebssystem, zielAdresse, zielPort, transportProtokoll); Main.debug.println("INVOKED-2 ("+this.hashCode()+") "+getClass()+" (Socket), constr: Socket("+betriebssystem+","+zielAdresse+","+zielPort+","+transportProtokoll+","+lokalerPort+")"); this.lokalerPort = lokalerPort; } /** * Hier wird das Attribut protokoll initialisiert. <br /> * Der Konstruktor ist <b> nicht blockierend</b>. * * @param betriebssystem * @param zielAdresse * @param zielPort * @throws VerbindungsException */ public Socket(InternetKnotenBetriebssystem betriebssystem, int lokalerPort, int transportProtokoll) throws VerbindungsException { Main.debug.println("INVOKED ("+this.hashCode()+") "+getClass()+" (Socket), constr: Socket("+betriebssystem+","+lokalerPort+","+transportProtokoll+")"); modus = PASSIV; if (transportProtokoll == IpPaket.TCP) protokoll = betriebssystem.holeTcp(); else protokoll = betriebssystem.holeUdp(); this.lokalerPort = lokalerPort; } /** * leerer Konstruktor wird von Unterklassen benoetigt */ public Socket() { Main.debug.println("INVOKED ("+this.hashCode()+") "+getClass()+" (Socket), constr: Socket()"); } /** Zum Versenden einer Nachricht ueber den Socket */ public abstract void senden(String nachricht) throws VerbindungsException, TimeOutException; /** Zum Empfangen einer Nachricht ueber den Socket */ public abstract String empfangen() throws VerbindungsException, TimeOutException; /** * Test, ob der uebergebene String eine gueltige IP-Adresse ist. * Zurueckgegeben wird die IP-Adresse ohne ueberfluessige Nullen. * * @param ip * die zu pruefende IP-Adresse * @return */ protected String ipCheck(String ip) { return IP.ipCheck(ip); } /** * Methode zum Versenden eines Segments an die Ziel-IP-Adresse mit Hilfe des * Transport-Protokolls * * @param segment * das zu sendende Segment */ protected void sende(Segment segment) { Main.debug.println("INVOKED ("+this.hashCode()+") "+getClass()+" (Socket), sende("+segment+")"); protokoll.senden(zielIp, quellIp, segment); } /** * Methode zum Schliessen eines Sockets. Damit ist gegebenenfalls auch * verbunden, dass der Port freigegeben wird. * */ public abstract void schliessen(); public abstract void verbinden() throws VerbindungsException, TimeOutException; public abstract boolean istVerbunden(); /** * Methode zum Eintragen eines Ports. Wenn es Teil eines Server-Sockets ist, * wird der Start- und Ziel-Port * * @throws SocketException * */ protected void eintragenPort() throws SocketException { Main.debug.println("INVOKED ("+this.hashCode()+") "+getClass()+" (Socket), eintragenPort()"); SocketSchnittstelle socket = null; if ( lokalerPort == -1 ) { lokalerPort = protokoll.reserviereFreienPort(this); } else { try { if (protokoll.isUsed(lokalerPort)) { socket = protokoll.holeSocket(lokalerPort); } } catch (SocketException e) { e.printStackTrace(Main.debug); } if (socket != null && socket instanceof ServerSocket) { ServerSocket serverSocket = (ServerSocket) socket; serverSocket.eintragenSocket(this); } else { if (!protokoll.reservierePort(lokalerPort, this)) throw new SocketException(); } } // Main.debug.println(getClass().toString() // + "\n\teintragenPort() aufgerufen" + "\n\tlokaler Port: " // + lokalerPort); } /** * Methode zum austragen des Ports des Sockets. Entweder wird der Port im * Betriebssystem freigegeben (modus == AKTIV) oder der Socket wird in der * Liste, die durch einen Server-Socket verwaltet wird, entfernt (modus == * PASSIV). * */ protected void austragenPort() { Main.debug.println("INVOKED ("+this.hashCode()+") "+getClass()+" (Socket), austragenPort()"); SocketSchnittstelle socket = null; try { socket = protokoll.holeSocket(lokalerPort); } catch (SocketException e) { e.printStackTrace(Main.debug); } if (socket != null && socket instanceof ServerSocket) { ServerSocket serverSocket = (ServerSocket) socket; serverSocket.austragenSocket(this); } else if (socket != null) { protokoll.gibPortFrei(lokalerPort); } } /** * Methode fuer den Zugriff auf die IP-Adresse des entfernten Sockets */ public String holeZielIPAdresse() { Main.debug.println("INVOKED ("+this.hashCode()+") "+getClass()+" (Socket), holeZielIPAdresse()"); return zielIp; } /** * Methode fuer den Zugriff auf den TCP-Port des entfernten Sockets */ public int holeZielPort() { Main.debug.println("INVOKED ("+this.hashCode()+") "+getClass()+" (Socket), holeZielPort()"); return zielPort; } public int holeLokalenPort() { return lokalerPort; } public void bind(String quellIp) { this.quellIp = quellIp; } public abstract String getStateAsString(); }