[Git][java-team/filius][upstream] New upstream version 2.12.1+ds1

Andreas B. Mundt (@andi) gitlab at salsa.debian.org
Wed Jun 10 15:17:29 BST 2026



Andreas B. Mundt pushed to branch upstream at Debian Java Maintainers / filius


Commits:
f6abad84 by Andreas B. Mundt at 2026-06-10T15:29:38+02:00
New upstream version 2.12.1+ds1
- - - - -


25 changed files:

- Changelog.md
- pom.xml
- src/main/java/filius/gui/anwendungssicht/GUIApplicationTerminalWindow.java
- src/main/java/filius/gui/anwendungssicht/GUIApplicationWebBrowserWindow.java
- src/main/java/filius/gui/anwendungssicht/GUIInstallationsDialog.java
- src/main/java/filius/gui/anwendungssicht/SatViewer.java
- src/main/java/filius/hardware/NetzwerkInterface.java
- src/main/java/filius/rahmenprogramm/Information.java
- src/main/java/filius/rahmenprogramm/nachrichten/Lauscher.java
- src/main/java/filius/software/dhcp/DHCPClient.java
- src/main/java/filius/software/dhcp/IpConfig.java
- src/main/java/filius/software/dns/DNSServer.java
- src/main/java/filius/software/nat/NatGateway.java
- src/main/java/filius/software/system/InternetKnotenBetriebssystem.java
- src/main/java/filius/software/system/SwitchFirmware.java
- src/main/java/filius/software/system/SystemSoftware.java
- src/main/java/filius/software/transportschicht/Segment.java
- src/main/java/filius/software/transportschicht/Socket.java
- src/main/java/filius/software/transportschicht/TcpSegment.java
- src/main/java/filius/software/transportschicht/UDPSocket.java
- src/main/java/filius/software/transportschicht/UdpSegment.java
- src/main/java/filius/software/vermittlungsschicht/IpPaket.java
- src/main/java/filius/software/www/WebBrowser.java
- src/main/resources/config/filius.ini
- src/test/java/filius/software/dhcp/DHCPClientTest.java


Changes:

=====================================
Changelog.md
=====================================
@@ -1,5 +1,26 @@
 # Changelog Filius
 
+## [2.12.1] - 2026-06-08
+### Fixed
+* Null pointer exception in case of ICMP 
+
+## [2.12.0] - 2026-06-06
+### Added
+* Configurable font size for terminal (in filius.ini) as experimental feature
+
+### Fixed
+* Uninstall of apps requires release of resources (e.g. port of active webserver)
+* DNS entries re-appeared after removal because of internal cache handling
+* One browser cache for all computers leads to unexpected behavior
+* Internal list of web browser of required resources was not reset and caused wrong http requests
+
+## [2.11.0] - 2026-05-10
+### Added
+* Use link-local addresses after unsuccessful DHCP retries
+
+### Changed
+* Windows installer uses os language for en/de/fr or en as default.
+
 ## [2.10.1] - 2026-02-15
 ### Fixed
  * Layer visualization under Windows was broken


=====================================
pom.xml
=====================================
@@ -2,13 +2,13 @@
 	<modelVersion>4.0.0</modelVersion>
 	<groupId>filius</groupId>
 	<artifactId>filius</artifactId>
-	<version>2.10.1</version>
+	<version>2.12.1</version>
 	<inceptionYear>2007</inceptionYear>
 	<properties>
-		<buildDate>15.02.2026</buildDate>
+		<buildDate>08.06.2026</buildDate>
 		<publisher>Stefan Freischlad</publisher>
 		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-		<junit.version>4.10</junit.version>
+		<junit.version>4.13</junit.version>
 		<mockito.version>4.11.0</mockito.version>
 		<fest.version>1.4</fest.version>
 		<htmlparser.version>2.1</htmlparser.version>
@@ -113,7 +113,7 @@
 		<dependency>
 			<groupId>org.springframework</groupId>
 			<artifactId>spring-web</artifactId>
-			<version>7.0.4</version>
+			<version>7.0.7</version>
 		</dependency>
 		<dependency>
 			<groupId>commons-cli</groupId>
@@ -267,6 +267,26 @@
 					<failOnError>false</failOnError>
 				</configuration>
 			</plugin>
+
+            <!-- Create a Zip-Archive for Platform Independent Delivery -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <version>2.3</version>
+                <configuration>
+                    <descriptors>
+                        <descriptor>src/assembly/assembly.xml</descriptor>
+                    </descriptors>
+                </configuration>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
 		</plugins>
 	</build>
 	<reporting>
@@ -274,7 +294,7 @@
 			<plugin>
 				<groupId>org.apache.maven.plugins</groupId>
 				<artifactId>maven-project-info-reports-plugin</artifactId>
-				<version>3.1.1</version>
+				<version>3.9.0</version>
 				<reportSets>
 					<reportSet>
 						<reports>
@@ -342,29 +362,11 @@
 							</execution>
 						</executions>
 					</plugin>
-					<!-- Create a Zip-Archive for Platform Independent Delivery -->
-					<plugin>
-						<groupId>org.apache.maven.plugins</groupId>
-						<artifactId>maven-assembly-plugin</artifactId>
-						<version>2.3</version>
-						<configuration>
-							<descriptors>
-								<descriptor>src/assembly/assembly.xml</descriptor>
-							</descriptors>
-						</configuration>
-						<executions>
-							<execution>
-								<phase>package</phase>
-								<goals>
-									<goal>single</goal>
-								</goals>
-							</execution>
-						</executions>
-					</plugin>
+
 					<plugin>
 						<groupId>org.codehaus.mojo</groupId>
 						<artifactId>exec-maven-plugin</artifactId>
-						<version>1.2</version>
+						<version>3.6.3</version>
 						<executions>
 							<execution>
 								<id>create installer</id>


=====================================
src/main/java/filius/gui/anwendungssicht/GUIApplicationTerminalWindow.java
=====================================
@@ -48,6 +48,7 @@ import javax.swing.ScrollPaneConstants;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
 
+import filius.rahmenprogramm.Information;
 import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -81,11 +82,15 @@ public class GUIApplicationTerminalWindow extends GUIApplicationWindow {
 
     private boolean multipleObserverEvents;
 
+    private int fontSize = 11;
+
     private ArrayList<String> commandHistory = new ArrayList<String>();
     private int commandHistoryPointer = -1;
 
     public GUIApplicationTerminalWindow(GUIDesktopPanel desktop, String appName) {
         super(desktop, appName);
+        fontSize = Information.getInformation().getTerminalFontSize();
+
         jobRunning = false;
         multipleObserverEvents = false;
 
@@ -94,7 +99,7 @@ public class GUIApplicationTerminalWindow extends GUIApplicationWindow {
         terminalField.setCaretColor(FOREGROUND);
         terminalField.setForeground(FOREGROUND);
         terminalField.setBackground(BACKGROUND);
-        terminalField.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 11));
+        terminalField.setFont(new Font(Font.MONOSPACED, Font.PLAIN, fontSize));
         terminalField.setFocusable(false);
         terminalField.setBorder(null);
         terminalField.setLineWrap(true);
@@ -104,7 +109,7 @@ public class GUIApplicationTerminalWindow extends GUIApplicationWindow {
         inputLabel = new JLabel(">");
         inputLabel.setBackground(BACKGROUND);
         inputLabel.setForeground(FOREGROUND);
-        inputLabel.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 11));
+        inputLabel.setFont(new Font(Font.MONOSPACED, Font.PLAIN, fontSize));
 
         Box terminalBox = Box.createHorizontalBox();
         terminalBox.setBackground(BACKGROUND);
@@ -160,7 +165,7 @@ public class GUIApplicationTerminalWindow extends GUIApplicationWindow {
         inputField.setForeground(FOREGROUND);
         inputField.setCaretColor(FOREGROUND);
         inputField.setBorder(null);
-        inputField.setFont(new Font("Courier New", Font.PLAIN, 11));
+        inputField.setFont(new Font("Courier New", Font.PLAIN, fontSize));
         inputField.setOpaque(false);
 
         inputField.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "doNothing");


=====================================
src/main/java/filius/gui/anwendungssicht/GUIApplicationWebBrowserWindow.java
=====================================
@@ -65,6 +65,8 @@ public class GUIApplicationWebBrowserWindow extends GUIApplicationWindow {
 
     private static final long serialVersionUID = 1L;
 
+    private WebBrowser webBrowser ;
+
     private JPanel browserPanel;
 
     private JTextField urlFeld;
@@ -75,7 +77,8 @@ public class GUIApplicationWebBrowserWindow extends GUIApplicationWindow {
 
     public GUIApplicationWebBrowserWindow(final GUIDesktopPanel desktop, String appName) {
         super(desktop, appName);
-        HTMLEditorKit ek;
+
+        webBrowser = (WebBrowser) holeAnwendung();
 
         browserPanel = new JPanel(new BorderLayout());
         add(browserPanel, BorderLayout.CENTER);
@@ -127,7 +130,7 @@ public class GUIApplicationWebBrowserWindow extends GUIApplicationWindow {
             public void keyTyped(KeyEvent arg0) {}
         });
 
-        ek = new HTMLEditorKit(); // Braucht er für SubmitEvent!
+        HTMLEditorKit ek = new HTMLEditorKit(); // Braucht er für SubmitEvent!
         ek.setAutoFormSubmission(false); // muss!
 
         anzeigeFeld = new JEditorPane();
@@ -138,17 +141,12 @@ public class GUIApplicationWebBrowserWindow extends GUIApplicationWindow {
                 + "<center><img src=\"browser_waterwolf_logo.png\" align=\"top\"></center>" + "</font>"
                 + "</body></html>");
 
-        // filius.rahmenprogramm.SzenarioVerwaltung.kopiereDatei(Information
-        // .getInformation().getProgrammPfad()
-        // + "gfx/desktop/browser_waterwolf_logo.png", Information
-        // .getInformation().getTempPfad()
-        // + "browser_waterwolf_logo.png");
         filius.rahmenprogramm.SzenarioVerwaltung.saveStream(
                 getClass().getResourceAsStream("/gfx/desktop/browser_waterwolf_logo.png"),
-                Information.getInformation().getTempPfad() + "browser_waterwolf_logo.png");
+                webBrowser.getBrowserCacheDirectory() + "browser_waterwolf_logo.png");
         try {
             ((HTMLDocument) anzeigeFeld.getDocument())
-                    .setBase(new URL("file:" + Information.getInformation().getTempPfad()));
+                    .setBase(new URL("file:" + webBrowser.getBrowserCacheDirectory()));
         } catch (MalformedURLException e1) {
             LOG.debug("", e1);
         }
@@ -210,12 +208,12 @@ public class GUIApplicationWebBrowserWindow extends GUIApplicationWindow {
 
         if (url != null) {
             if (postDaten == null) {
-                ((WebBrowser) holeAnwendung()).holeWebseite(url);
+                webBrowser.holeWebseite(url);
             } else {
-                ((WebBrowser) holeAnwendung()).holeWebseite(url, postDaten);
+                webBrowser.holeWebseite(url, postDaten);
             }
             if (url.getHost() == null || url.getHost().equals("")) {
-                host = ((WebBrowser) holeAnwendung()).holeHost();
+                host = webBrowser.holeHost();
             } else {
                 host = url.getHost();
             }


=====================================
src/main/java/filius/gui/anwendungssicht/GUIInstallationsDialog.java
=====================================
@@ -1,9 +1,9 @@
 /*
  ** 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): 
+ **     members (2006-2007):
  **         André Asschoff, Johannes Bade, Carsten Dittich, Thomas Gerding,
  **         Nadja Haßler, Ernst Johannes Klebert, Michell Weyer
  **     supervisors:
@@ -14,12 +14,12 @@
  ** 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/>.
  */
@@ -200,7 +200,7 @@ public class GUIInstallationsDialog extends GUIApplicationWindow implements I18n
             vLoeschen.add((String) lmVerfuegbar.get(i));
         }
 
-        for (Enumeration<String> e = vLoeschen.elements(); e.hasMoreElements();) {
+        for (Enumeration<String> e = vLoeschen.elements(); e.hasMoreElements(); ) {
             String oZuLoeschen = e.nextElement();
             lmVerfuegbar.removeElement(oZuLoeschen);
         }
@@ -215,7 +215,7 @@ public class GUIInstallationsDialog extends GUIApplicationWindow implements I18n
             hinzu.add((String) lmInstalliert.getElementAt(i));
         }
 
-        for (Enumeration<String> e = hinzu.elements(); e.hasMoreElements();) {
+        for (Enumeration<String> e = hinzu.elements(); e.hasMoreElements(); ) {
             String hinzuObjekt = e.nextElement();
             lmInstalliert.removeElement(hinzuObjekt);
         }
@@ -228,21 +228,14 @@ public class GUIInstallationsDialog extends GUIApplicationWindow implements I18n
         for (Map<String, String> appInfo : programme) {
             for (int i = 0; i < lmInstalliert.getSize(); i++) {
                 if (lmInstalliert.getElementAt(i).equals(appInfo.get("Anwendung"))
-                        && bs.holeSoftware(appInfo.get("Klasse").toString()) == null) {
+                    && bs.holeSoftware(appInfo.get("Klasse").toString()) == null) {
                     bs.installAppIfAvailable(appInfo.get("Klasse").toString());
-
-                    anwendung = bs.holeSoftware(appInfo.get("Klasse").toString());
-                    anwendung.starten();
                 }
             }
 
             for (int i = 0; i < lmVerfuegbar.getSize(); i++) {
                 if (lmVerfuegbar.getElementAt(i).equals(appInfo.get("Anwendung"))) {
-                    anwendung = bs.holeSoftware(appInfo.get("Klasse").toString());
-                    if (anwendung != null) {
-                        anwendung.beenden();
-                        bs.entferneSoftware(appInfo.get("Klasse").toString());
-                    }
+                    bs.entferneSoftware(appInfo.get("Klasse").toString());
                 }
             }
         }
@@ -250,5 +243,6 @@ public class GUIInstallationsDialog extends GUIApplicationWindow implements I18n
     }
 
     @Override
-    public void update(Observable arg0, Object arg1) {}
+    public void update(Observable arg0, Object arg1) {
+    }
 }


=====================================
src/main/java/filius/gui/anwendungssicht/SatViewer.java
=====================================
@@ -95,7 +95,7 @@ public class SatViewer extends JDialog implements I18n, PropertyChangeListener {
         return sw;
     }
 
-    private void updateSat() {
+    private synchronized void updateSat() {
         dtm.setRowCount(0);
         for (Vector<String> zeile : ((SwitchFirmware) sw.getSystemSoftware()).holeSAT()) {
             dtm.addRow(zeile);


=====================================
src/main/java/filius/hardware/NetzwerkInterface.java
=====================================
@@ -1,9 +1,9 @@
 /*
  ** 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): 
+ **     members (2006-2007):
  **         André Asschoff, Johannes Bade, Carsten Dittich, Thomas Gerding,
  **         Nadja Haßler, Ernst Johannes Klebert, Michell Weyer
  **     supervisors:
@@ -14,12 +14,12 @@
  ** 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/>.
  */
@@ -35,10 +35,11 @@ import filius.rahmenprogramm.Information;
 import filius.software.vermittlungsschicht.IP;
 
 public class NetzwerkInterface implements Serializable {
-    private static Logger LOG = LoggerFactory.getLogger(NetzwerkInterface.class);
+    private static final Logger LOG = LoggerFactory.getLogger(NetzwerkInterface.class);
 
-    private static final long serialVersionUID = 1L;
-    /** The node that the interface belongs to */
+    /**
+     * The node that the interface belongs to
+     */
     private InternetKnoten node;
     private String mac;
     private String ip;
@@ -50,7 +51,7 @@ public class NetzwerkInterface implements Serializable {
 
     public NetzwerkInterface() {
         LOG.trace("INVOKED (" + this.hashCode() + ") " + getClass()
-                + " (NetzwerkInterface), constr: NetzwerkInterface()");
+            + " (NetzwerkInterface), constr: NetzwerkInterface()");
         setMac(Information.getInformation().holeFreieMACAdresse());
         // set initial IP address to the same value for all new devices
         // QUESTION: Is this actually wanted for educational reasons?
@@ -70,10 +71,6 @@ public class NetzwerkInterface implements Serializable {
         this.node = node;
     }
 
-    private InternetKnoten getNode() {
-        return this.node;
-    }
-
     /**
      * This method is used to mark the MAC address as transient property in order to avoid use of the same MAC address
      * if the same project is opened twice.
@@ -94,7 +91,6 @@ public class NetzwerkInterface implements Serializable {
     // e.printStackTrace();
     // }
     // }
-
     public Port getPort() {
         return anschluss;
     }
@@ -105,7 +101,7 @@ public class NetzwerkInterface implements Serializable {
 
     /**
      * IP-Adresse des DNS-Servers, der zur Aufloesung von Domainnamen verwendet wird.
-     * 
+     * <p>
      * NOTE: die IP-Adresse des DNS-Servers ist kein Parameter des Netzwerk-Interfaces, wird aber aus Gruenden der
      * Kompatibilitaet hier verwaltet. Jedes Netzwerk-Interface der gleichen Komponente sollte hier den gleichen Wert
      * haben!
@@ -116,11 +112,12 @@ public class NetzwerkInterface implements Serializable {
 
     /**
      * IP-Adresse des DNS-Servers, der zur Aufloesung von Domainnamen verwendet wird.
-     * 
+     *
      * @deprecated die IP-Adresse des DNS-Servers ist kein Parameter des Netzwerk-Interfaces, wird aber aus Gruenden der
-     *             Kompatibilitaet hier verwaltet. Jedes Netzwerk-Interface der gleichen Komponente sollte hier den
-     *             gleichen Wert haben!
+     * Kompatibilitaet hier verwaltet. Jedes Netzwerk-Interface der gleichen Komponente sollte hier den
+     * gleichen Wert haben!
      */
+    @Deprecated
     public void setDns(String dns) {
         this.dns = dns;
     }
@@ -155,7 +152,7 @@ public class NetzwerkInterface implements Serializable {
     /**
      * IP-Adresse des Standard-Gateways. Dorthin werden alle Pakete gesendet, fuer dessen Zieladresse kein anderer
      * Eintrag in der Weiterleitungstabelle vorhanden ist.
-     * 
+     * <p>
      * NOTE: die IP-Adresse des Standard-Gateways ist kein Parameter des Netzwerk-Interfaces, wird aber aus Gruenden der
      * Kompatibilitaet hier verwaltet. Jedes Netzwerk-Interface der gleichen Komponente sollte hier den gleichen Wert
      * haben!
@@ -167,11 +164,12 @@ public class NetzwerkInterface implements Serializable {
     /**
      * IP-Adresse des Standard-Gateways. Dorthin werden alle Pakete gesendet, fuer dessen Zieladresse kein anderer
      * Eintrag in der Weiterleitungstabelle vorhanden ist.
-     * 
+     *
      * @deprecated die IP-Adresse des Standard-Gateways ist kein Parameter des Netzwerk-Interfaces, wird aber aus
-     *             Gruenden der Kompatibilitaet hier verwaltet. Jedes Netzwerk-Interface der gleichen Komponente sollte
-     *             hier den gleichen Wert haben!
+     * Gruenden der Kompatibilitaet hier verwaltet. Jedes Netzwerk-Interface der gleichen Komponente sollte
+     * hier den gleichen Wert haben!
      */
+    @Deprecated
     public void setGateway(String gateway) {
         this.gateway = gateway;
     }


=====================================
src/main/java/filius/rahmenprogramm/Information.java
=====================================
@@ -146,6 +146,8 @@ public class Information implements Serializable {
 
     private boolean layerVisualization = false;
 
+    private int terminalFontSize = 11;
+
     public boolean isLayerVisualization() {
         return layerVisualization;
     }
@@ -170,6 +172,8 @@ public class Information implements Serializable {
         return System.getProperty("user.home");
     }
 
+    public int getTerminalFontSize() { return terminalFontSize; }
+
     /**
      * ensure a correct and well functioning path to write all necessary data
      */
@@ -638,10 +642,14 @@ public class Information implements Serializable {
                                 } else if (configKey.equalsIgnoreCase("native-look-n-feel")) {
                                     if (configValue.trim().equals("1")) {
                                         Main.activateNativeLookAndFeel();
+                                    } else {
+                                        LOG.info("Ignore invalid value '{}' for {}.", configValue, configKey);
                                     }
                                 } else if (configKey.equalsIgnoreCase("posix-behaviour")) {
                                     if (configValue.trim().equals("1")) {
                                         posixCommandLineToolBehaviour = true;
+                                    } else {
+                                        LOG.info("Ignore invalid value '{}' for {}.", configValue, configKey);
                                     }
                                 } else if (configKey.equalsIgnoreCase("desktop-mode")) {
                                     desktopWindowMode = GUIDesktopWindow.Mode
@@ -651,6 +659,8 @@ public class Information implements Serializable {
                                         this.oldExchangeDialog = true;
                                     } else if (configValue.trim().equals("0")) {
                                         this.oldExchangeDialog = false;
+                                    } else {
+                                        LOG.info("Ignore invalid value '{}' for {}.", configValue, configKey);
                                     }
                                 } else if (configKey.equalsIgnoreCase("software-wizard")) {
                                     if (configValue.trim().equals("1")) {
@@ -659,20 +669,40 @@ public class Information implements Serializable {
                                         softwareWizardMode = FeatureMode.FORCE_DISABLE;
                                     } else if (configValue.trim().equals("2")) {
                                         softwareWizardMode = FeatureMode.AUTO;
+                                    } else {
+                                        LOG.info("Ignore invalid value '{}' for {}.", configValue, configKey);
                                     }
                                 } else if (configKey.equalsIgnoreCase("pane-width")) {
                                     try {
                                         width = Integer.parseInt(configValue);
-                                    } catch (NumberFormatException e) {}
+                                    } catch (NumberFormatException e) {
+                                        LOG.info("Ignore invalid value '{}' for {}.", configValue, configKey);
+                                    }
                                 } else if (configKey.equalsIgnoreCase("pane-height")) {
                                     try {
                                         height = Integer.parseInt(configValue);
-                                    } catch (NumberFormatException e) {}
+                                    } catch (NumberFormatException e) {
+                                        LOG.info("Ignore invalid value '{}' for {}.", configValue, configKey);
+                                    }
                                 } else if (configKey.equalsIgnoreCase("gateway")) {
                                     if (configValue.trim().equals("1")) {
                                         this.gatewayAvailable = true;
                                     } else if (configValue.trim().equals("0")) {
                                         this.gatewayAvailable = false;
+                                    } else {
+                                        LOG.info("Ignore invalid value '{}' for {}.", configValue, configKey);
+                                    }
+                                } else if (configKey.equalsIgnoreCase("terminal-font-size")) {
+                                    int configSize = terminalFontSize;
+                                    try {
+                                        configSize = Integer.parseInt(configValue);
+                                    } catch (NumberFormatException e) {
+                                        LOG.info("Ignore invalid value '{}' for {}.", configValue, configKey);
+                                    }
+                                    if (configSize >= 10 && configSize <= 20) {
+                                        terminalFontSize = configSize;
+                                    } else {
+                                        LOG.info("Ignore invalid value '{}' for {}.", configValue, configKey);
                                     }
                                 }
                             }


=====================================
src/main/java/filius/rahmenprogramm/nachrichten/Lauscher.java
=====================================
@@ -161,7 +161,7 @@ public class Lauscher implements I18n {
         LOG.trace("INVOKED (" + this.hashCode() + ") " + getClass() + ", addDatenEinheit(" + interfaceId + "," + frame
                 + ")");
         if (!frame.isReadByLauscherForMac(interfaceId)) {
-            Object[] frameMitZeitstempel = frameWithTimestamp(frame);
+            Object[] frameMitZeitstempel = frameWithTimestamp(frame.clone());
 
             LinkedList<Object[]> liste = (LinkedList<Object[]>) datenEinheiten.get(interfaceId);
             if (liste == null) {
@@ -187,7 +187,7 @@ public class Lauscher implements I18n {
     protected Object[] frameWithTimestamp(EthernetFrame frame) {
         Object[] frameMitZeitstempel = new Object[2];
         frameMitZeitstempel[0] = Long.valueOf(System.currentTimeMillis());
-        frameMitZeitstempel[1] = frame.clone();
+        frameMitZeitstempel[1] = frame;
         return frameMitZeitstempel;
     }
 


=====================================
src/main/java/filius/software/dhcp/DHCPClient.java
=====================================
@@ -1,9 +1,9 @@
 /*
  ** 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): 
+ **     members (2006-2007):
  **         André Asschoff, Johannes Bade, Carsten Dittich, Thomas Gerding,
  **         Nadja Haßler, Ernst Johannes Klebert, Michell Weyer
  **     supervisors:
@@ -14,25 +14,17 @@
  ** 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.dhcp;
 
-import static filius.software.dhcp.DHCPClient.State.ASSIGN_IP;
-import static filius.software.dhcp.DHCPClient.State.DECLINE;
-import static filius.software.dhcp.DHCPClient.State.DISCOVER;
-import static filius.software.dhcp.DHCPClient.State.FINISH;
-import static filius.software.dhcp.DHCPClient.State.INIT;
-import static filius.software.dhcp.DHCPClient.State.REQUEST;
-import static filius.software.dhcp.DHCPClient.State.VALIDATE;
-
 import java.util.ArrayList;
 import java.util.List;
 
@@ -54,21 +46,26 @@ import filius.software.system.SystemSoftware;
 import filius.software.transportschicht.UDPSocket;
 import filius.software.vermittlungsschicht.ARP;
 
+import static filius.software.dhcp.DHCPClient.State.*;
+
 public class DHCPClient extends ClientAnwendung {
     private static Logger LOG = LoggerFactory.getLogger(DHCPClient.class);
 
     enum State {
-        ASSIGN_IP, FINISH, DISCOVER, REQUEST, VALIDATE, DECLINE, INIT
+        DHCP_ASSIGN_IP, SUCCEED, DHCP_DISCOVER, DHCP_REQUEST, DHCP_VALIDATE, DHCP_DECLINE, DHCP_INIT,
+        LINK_LOCAL_INIT, LINK_LOCAL_VALIDATE, LINK_LOCAL_ANNOUNCE
     }
 
     private static final String IP_ADDRESS_CURRENT_NETWORK = "0.0.0.0";
-    private static final int MAX_ERROR_COUNT = 10;
+    private static final int DHCP_MAX_ERROR_COUNT = 5;
+    private static final int LINK_LOCAL_MAX_ERROR_COUNT = 5;
 
-    private State zustand;
+    public static final String LINK_LOCAL_ADDRESS_PREFIX = "169.254.1.";
+    public static final String LINK_LOCAL_SUBNET_MASK = "255.255.0.0";
 
     public void starten() {
         LOG.debug(
-                "INVOKED (" + this.hashCode() + ", T" + this.getId() + ") " + getClass() + " (DHCPClient), starten()");
+            "INVOKED (" + this.hashCode() + ", T" + this.getId() + ") " + getClass() + " (DHCPClient), starten()");
         super.starten();
 
         ausfuehren("configure", null);
@@ -87,15 +84,15 @@ public class DHCPClient extends ClientAnwendung {
                     if (dhcpServer.isAktiv() && !dhcpServer.isStarted()) {
                         activeDHCPserversStarted = false;
                         LOG.debug("DHCP client is waiting for DHCP server on '"
-                                + dhcpServer.getSystemSoftware().getKnoten().holeAnzeigeName()
-                                + "'. Server has NOT yet started.");
+                            + dhcpServer.getSystemSoftware().getKnoten().holeAnzeigeName()
+                            + "'. Server has NOT yet started.");
                         break;
                     }
                 }
                 Thread.sleep(100);
             }
             LOG.debug("DHCP client on '" + getSystemSoftware().getKnoten().holeAnzeigeName()
-                    + "' finished check for DHCP server.");
+                + "' finished check for DHCP server.");
         } catch (InterruptedException e) {
             LOG.debug("", e);
         }
@@ -117,9 +114,9 @@ public class DHCPClient extends ClientAnwendung {
 
     public void configure() {
         LOG.trace("INVOKED (" + this.hashCode() + ", T" + this.getId() + ") " + getClass()
-                + " (DHCPClient), starteDatenaustausch()");
-        int fehlerzaehler = 0;
-        zustand = INIT;
+            + " (DHCPClient), starteDatenaustausch()");
+        int failureCount = 0;
+        State zustand = DHCP_INIT;
 
         String oldIpAddress = resetIpConfig();
         updateOberserver();
@@ -127,52 +124,91 @@ public class DHCPClient extends ClientAnwendung {
         IpConfig config = null;
         UDPSocket udpSocket = null;
         InternetKnotenBetriebssystem operatingSystem = (InternetKnotenBetriebssystem) getSystemSoftware();
-        while (zustand != FINISH && fehlerzaehler < MAX_ERROR_COUNT && running) {
+        while (zustand != SUCCEED && running) {
             try {
                 switch (zustand) {
-                case INIT:
-                    waitUntilDhcpServerStarted();
-                    udpSocket = initUdpSocket();
-                    zustand = DISCOVER;
-                    break;
-                case DISCOVER:
-                    config = discover(udpSocket, operatingSystem.dhcpEnabledMACAddress(), Verbindung.holeRTT());
-                    zustand = VALIDATE;
-                    break;
-                case VALIDATE:
-                    boolean validAddress = validateOfferedAddress(getSystemSoftware().holeARP(), config.getIpAddress());
-                    zustand = validAddress ? REQUEST : DECLINE;
-                    break;
-                case DECLINE:
-                    decline(udpSocket, operatingSystem.dhcpEnabledMACAddress(), config, Verbindung.holeRTT());
-                    zustand = DISCOVER;
-                    break;
-                case REQUEST:
-                    boolean acknowledged = request(udpSocket, operatingSystem.dhcpEnabledMACAddress(), config,
+                    case DHCP_INIT:
+                        waitUntilDhcpServerStarted();
+                        udpSocket = initUdpSocket();
+                        zustand = DHCP_DISCOVER;
+                        break;
+                    case DHCP_DISCOVER:
+                        config = discover(udpSocket, operatingSystem.dhcpEnabledMACAddress(), Verbindung.holeRTT());
+                        zustand = DHCP_VALIDATE;
+                        break;
+                    case DHCP_VALIDATE:
+                        boolean validAddress = validateOfferedAddress(getSystemSoftware().holeARP(), config.getIpAddress());
+                        zustand = validAddress ? DHCP_REQUEST : DHCP_DECLINE;
+                        break;
+                    case DHCP_DECLINE:
+                        decline(udpSocket, operatingSystem.dhcpEnabledMACAddress(), config, Verbindung.holeRTT());
+                        zustand = DHCP_DISCOVER;
+                        break;
+                    case DHCP_REQUEST:
+                        boolean acknowledged = request(udpSocket, operatingSystem.dhcpEnabledMACAddress(), config,
                             Verbindung.holeRTT());
-                    zustand = acknowledged ? ASSIGN_IP : DISCOVER;
-                    break;
-                case ASSIGN_IP:
-                    operatingSystem.setzeIPAdresse(config.getIpAddress());
-                    operatingSystem.setzeNetzmaske(config.getSubnetMask());
-                    operatingSystem.setStandardGateway(config.getRouter());
-                    operatingSystem.setDNSServer(config.getDnsServer());
-                default:
-                    zustand = FINISH;
+                        zustand = acknowledged ? DHCP_ASSIGN_IP : DHCP_DISCOVER;
+                        break;
+                    case DHCP_ASSIGN_IP:
+                        operatingSystem.setzeIPAdresse(config.getIpAddress());
+                        operatingSystem.setzeNetzmaske(config.getSubnetMask());
+                        operatingSystem.setStandardGateway(config.getGateway());
+                        operatingSystem.setDNSServer(config.getDnsServer());
+                        zustand = SUCCEED;
+                        LOG.info("New ip configuration via DHCP: {} / {}, gateway: {}, dns: {}",
+                            config.getIpAddress(), config.getSubnetMask(), config.getGateway(), config.getDnsServer());
+                        break;
+                    case LINK_LOCAL_INIT:
+                        config = selectArbitraryLinkLocalAddress(operatingSystem);
+                        zustand = LINK_LOCAL_VALIDATE;
+                        break;
+                    case LINK_LOCAL_VALIDATE:
+                        boolean validLinkLocalAddress = validateOfferedAddress(getSystemSoftware().holeARP(), config.getIpAddress());
+                        if (validLinkLocalAddress) {
+                            operatingSystem.setzeIPAdresse(config.getIpAddress());
+                            operatingSystem.setzeNetzmaske(config.getSubnetMask());
+                            operatingSystem.setStandardGateway("");
+                            zustand = LINK_LOCAL_ANNOUNCE;
+                        } else {
+                            failureCount++;
+                            zustand = LINK_LOCAL_INIT;
+                        }
+                        break;
+                    case LINK_LOCAL_ANNOUNCE:
+                        operatingSystem.holeARP().sendArpReply(operatingSystem.primaryMACAddress(), operatingSystem.primaryIPAdresse(),
+                            null, IP_ADDRESS_CURRENT_NETWORK, operatingSystem.primaryNetworkInterface());
+                        zustand = SUCCEED;
+                        LOG.info("New ip configuration via link local: {} / {}", config.getIpAddress(), config.getSubnetMask());
+                        break;
                 }
             } catch (NoValidDhcpResponseException | TimeOutException | VerbindungsException e) {
-                fehlerzaehler++;
+                failureCount++;
+
+                if (failureCount == DHCP_MAX_ERROR_COUNT) {
+                    LOG.info("Got no configuration via DHCP. Init Address with link local.");
+                    zustand = LINK_LOCAL_INIT;
+                } else if (failureCount == DHCP_MAX_ERROR_COUNT + LINK_LOCAL_MAX_ERROR_COUNT) {
+                    LOG.info("Could not init link-local ip address.");
+                    break;
+                }
             }
         }
-        if (fehlerzaehler == MAX_ERROR_COUNT || !running) {
-            LOG.error("kein DHCPACK erhalten");
-            operatingSystem.setzeIPAdresse(oldIpAddress);
-        }
         udpSocket.schliessen();
 
         updateOberserver();
     }
 
+    private IpConfig selectArbitraryLinkLocalAddress(InternetKnotenBetriebssystem operatingSystem) {
+        long lastByte=0;
+        for (int i=0; i<500 && lastByte==0; i++) {
+             lastByte = Math.round(Math.random() * 253f) + 1;
+             if (!operatingSystem.holeARP().holeARPTabelle(LINK_LOCAL_ADDRESS_PREFIX + lastByte).isEmpty()) {
+                 lastByte = 0;
+             }
+        }
+        return new IpConfig(LINK_LOCAL_ADDRESS_PREFIX + lastByte, LINK_LOCAL_SUBNET_MASK);
+    }
+
     private void updateOberserver() {
         InternetKnotenBetriebssystem operatingSystem = (InternetKnotenBetriebssystem) getSystemSoftware();
         Knoten node = operatingSystem.getKnoten();
@@ -194,49 +230,50 @@ public class DHCPClient extends ClientAnwendung {
     }
 
     boolean request(UDPSocket socket, String clientMacAddress, IpConfig config, long socketTimeoutMillis)
-            throws NoValidDhcpResponseException, TimeOutException {
+        throws NoValidDhcpResponseException, TimeOutException {
         socket.sendeBroadcast(IP_ADDRESS_CURRENT_NETWORK, DHCPMessage
-                .createRequestMessage(clientMacAddress, config.getIpAddress(), config.getDhcpServer()).toString());
+            .createRequestMessage(clientMacAddress, config.getIpAddress(), config.getDhcpServer()).toString());
 
         DHCPMessage result = receiveResponse(socket, socketTimeoutMillis, clientMacAddress, config.getDhcpServer(),
-                DHCPMessageType.ACK, DHCPMessageType.NACK);
+            DHCPMessageType.ACK, DHCPMessageType.NACK);
 
         return null != result && result.getType() == DHCPMessageType.ACK;
     }
 
     void decline(UDPSocket socket, String clientMacAddress, IpConfig config, long socketTimeoutMillis)
-            throws NoValidDhcpResponseException {
+        throws NoValidDhcpResponseException {
         socket.sendeBroadcast(IP_ADDRESS_CURRENT_NETWORK, DHCPMessage
-                .createDeclineMessage(clientMacAddress, config.getIpAddress(), config.getDhcpServer()).toString());
+            .createDeclineMessage(clientMacAddress, config.getIpAddress(), config.getDhcpServer()).toString());
     }
 
     IpConfig discover(UDPSocket socket, String clientMacAddress, long socketTimeoutMillis)
-            throws NoValidDhcpResponseException, TimeOutException {
+        throws NoValidDhcpResponseException, TimeOutException {
         socket.sendeBroadcast(IP_ADDRESS_CURRENT_NETWORK,
-                DHCPMessage.createDiscoverMessage(clientMacAddress).toString());
+            DHCPMessage.createDiscoverMessage(clientMacAddress).toString());
 
         DHCPMessage offer = receiveResponse(socket, socketTimeoutMillis, clientMacAddress, null, DHCPMessageType.OFFER);
 
         return new IpConfig(offer.getYiaddr(), offer.getRouter(), offer.getSubnetMask(), offer.getDnsServer(),
-                offer.getServerIdentifier());
+            offer.getServerIdentifier());
     }
 
     private DHCPMessage receiveResponse(UDPSocket socket, long socketTimeoutMillis, String clientMacAddress,
-            String serverIdentifier, DHCPMessageType... messageTypes)
-            throws NoValidDhcpResponseException, TimeOutException {
+                                        String serverIdentifier, DHCPMessageType... messageTypes)
+        throws NoValidDhcpResponseException, TimeOutException {
         DHCPMessage responseMessage = null;
         long start = System.currentTimeMillis();
         long duration = 0;
         do {
             String response = socket.empfangen(socketTimeoutMillis - duration);
             if (null == response) {
+                LOG.debug("{}: DHCP received empty response", getSystemSoftware().getKnoten().holeAnzeigeName());
                 throw new TimeOutException("No response from DHCP server received.");
             }
             responseMessage = DHCPMessage.fromString(response);
             boolean invalidMessageType = !ArrayUtils.contains(messageTypes, responseMessage.getType());
             boolean forOtherClient = !clientMacAddress.equalsIgnoreCase(responseMessage.getChaddr());
             boolean fromOtherServer = null != serverIdentifier
-                    && !serverIdentifier.equals(responseMessage.getServerIdentifier());
+                && !serverIdentifier.equals(responseMessage.getServerIdentifier());
             if (invalidMessageType || forOtherClient || fromOtherServer) {
                 responseMessage = null;
             }


=====================================
src/main/java/filius/software/dhcp/IpConfig.java
=====================================
@@ -2,25 +2,30 @@ package filius.software.dhcp;
 
 public class IpConfig {
     private String ipAddress;
-    private String router;
+    private String gateway;
     private String subnetMask;
     private String dnsServer;
     private String dhcpServer;
 
-    IpConfig(String ipAddress, String router, String subnetMask, String dnsServer, String dhcpServer) {
+    IpConfig(String ipAddress, String gateway, String subnetMask, String dnsServer, String dhcpServer) {
         this.ipAddress = ipAddress;
-        this.router = router;
+        this.gateway = gateway;
         this.subnetMask = subnetMask;
         this.dnsServer = dnsServer;
         this.dhcpServer = dhcpServer;
     }
 
+    IpConfig(String ipAddress, String subnetMask) {
+        this.ipAddress = ipAddress;
+        this.subnetMask = subnetMask;
+    }
+
     public String getIpAddress() {
         return ipAddress;
     }
 
-    public String getRouter() {
-        return router;
+    public String getGateway() {
+        return gateway;
     }
 
     public String getSubnetMask() {


=====================================
src/main/java/filius/software/dns/DNSServer.java
=====================================
@@ -257,15 +257,15 @@ public class DNSServer extends UDPServerAnwendung {
     public void loescheResourceRecord(String domainname, String typ) {
         LOG.trace("INVOKED (" + this.hashCode() + ", T" + this.getId() + ") " + getClass()
                 + " (DNSServer), loescheResourceRecord(" + domainname + "," + typ + ")");
-        List<ResourceRecord> rrList = leseRecordListe();
+        cachedRrList = leseRecordListe();
 
-        for (ResourceRecord rr : rrList) {
+        for (ResourceRecord rr : cachedRrList) {
             if (rr.getDomainname().equalsIgnoreCase(domainname) && rr.getType().equals(typ)) {
-                rrList.remove(rr);
+                cachedRrList.remove(rr);
                 break;
             }
         }
-        this.schreibeRecordListe(rrList);
+        this.schreibeRecordListe(cachedRrList);
     }
 
     protected void neuerMitarbeiter(Socket socket) {


=====================================
src/main/java/filius/software/nat/NatGateway.java
=====================================
@@ -1,9 +1,9 @@
 /*
  ** 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): 
+ **     members (2006-2007):
  **         André Asschoff, Johannes Bade, Carsten Dittich, Thomas Gerding,
  **         Nadja Haßler, Ernst Johannes Klebert, Michell Weyer
  **     supervisors:
@@ -14,12 +14,12 @@
  ** 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/>.
  */
@@ -46,9 +46,9 @@ public class NatGateway extends Firewall implements I18n {
     protected void initFirewallThreads() {
         Gateway gateway = (Gateway) getSystemSoftware().getKnoten();
         addAndStartThread(new NatGatewayLANThread(this, gateway.holeLANInterface(), gateway.holeWANInterface(),
-                this.betriebssystem));
+            this.betriebssystem));
         addAndStartThread(new NatGatewayWANThread(this, gateway.holeWANInterface(), gateway.holeLANInterface(),
-                this.betriebssystem));
+            this.betriebssystem));
         LOG.debug("Threads for WAN and LAN nic are started on {}", gateway.getName());
     }
 
@@ -57,9 +57,9 @@ public class NatGateway extends Firewall implements I18n {
         Gateway gateway = (Gateway) getSystemSoftware().getKnoten();
         if (!natTable.hasConnection(lanAddress)) {
             if (protocol == IpPaket.TCP) {
-            	wanPort = getSystemSoftware().holeTcp().reserviereFreienPort();
+                wanPort = getSystemSoftware().holeTcp().reserviereFreienPort();
             } else if (protocol == IpPaket.UDP) {
-            	wanPort = getSystemSoftware().holeUdp().reserviereFreienPort();
+                wanPort = getSystemSoftware().holeUdp().reserviereFreienPort();
             }
             LOG.debug("New connection in NAT table: protocol={}, port={}, address={}", protocol, wanPort, lanAddress);
             natTable.addDynamic(wanPort, wanIpAddress, protocol, lanAddress, NatType.DynamicEntry);
@@ -70,60 +70,65 @@ public class NatGateway extends Firewall implements I18n {
 
     public void replaceSource(IpPaket packet) {
         Gateway gateway = (Gateway) getSystemSoftware().getKnoten();
+        int newSourcePort = 0, oldSourcePort = 0;
         if (packet.getProtocol() == IpPaket.TCP || packet.getProtocol() == IpPaket.UDP) {
-            InetAddress lanAddress = new InetAddress(packet.getSender(), packet.getSegment().getQuellPort(),
-                    packet.getProtocol());
-            int port = natTable.findPort(lanAddress);
-            packet.getSegment().setQuellPort(port);
+            oldSourcePort = packet.getSegment().getQuellPort();
+            InetAddress lanAddress = new InetAddress(packet.getSender(), oldSourcePort,
+                packet.getProtocol());
+            newSourcePort = natTable.findPort(lanAddress);
+            packet.getSegment().setQuellPort(newSourcePort);
         }
-        packet.setSender(gateway.holeWANInterface().getIp());
+        String newSourceAddress = gateway.holeWANInterface().getIp();
+        LOG.debug("NAT substitution SOURCE (protocol={}): {}->{} / {}->{}", packet.getProtocol(), packet.getSender(), newSourceAddress, oldSourcePort, newSourcePort);
+        packet.setSender(newSourceAddress);
     }
 
     public void replaceDestination(IpPaket packet) {
-    	int protocol = packet.getProtocol();
-    	int port = 0;
+        int protocol = packet.getProtocol();
+        int port = 0;
         String sender = "";
-        if ((protocol == IpPaket.TCP)||(protocol == IpPaket.UDP)){
-        	port = packet.getSegment().getZielPort();
-        	sender = packet.getSender();
+        if ((protocol == IpPaket.TCP) || (protocol == IpPaket.UDP)) {
+            port = packet.getSegment().getZielPort();
+            sender = packet.getSender();
         } else if (protocol == IcmpPaket.ICMP_PROTOCOL) {
-        	if (((IcmpPaket) packet).getPayload() != null) {
-        		IpPaket payload = ((IcmpPaket) packet).getPayload();
-        		sender = payload.getEmpfaenger();
-        		if (payload instanceof IcmpPaket) {
-        			port = ((IcmpPaket) payload).getIdentifier();
-        		} else {
-        			port = payload.getSegment().getQuellPort();
-        		}
-        		protocol = payload.getProtocol();
-        	} else {
-        		port = ((IcmpPaket)packet).getIdentifier();
-        		sender = packet.getSender();
-        	}
+            if (((IcmpPaket) packet).getPayload() != null) {
+                IpPaket payload = ((IcmpPaket) packet).getPayload();
+                sender = payload.getEmpfaenger();
+                if (payload instanceof IcmpPaket) {
+                    port = ((IcmpPaket) payload).getIdentifier();
+                } else {
+                    port = payload.getSegment().getQuellPort();
+                }
+                protocol = payload.getProtocol();
+            } else {
+                port = ((IcmpPaket) packet).getIdentifier();
+                sender = packet.getSender();
+            }
         }
         InetAddress dest = natTable.find(port, sender, protocol);
-    	protocol = packet.getProtocol();
+        protocol = packet.getProtocol();
         Gateway gateway = (Gateway) getSystemSoftware().getKnoten();
         ((GatewayFirmware) gateway.getSystemSoftware()).fireNATPropertyChange();
         if (dest != null) {
+            LOG.debug("NAT substitution dest (protocol={}): {}->{} / {}->{}", protocol, packet.getEmpfaenger(), dest.getIpAddress(), port, dest.getPort());
             packet.setEmpfaenger(dest.getIpAddress());
             if (packet.getProtocol() == IpPaket.TCP || packet.getProtocol() == IpPaket.UDP) {
                 packet.getSegment().setZielPort(dest.getPort());
             } else {
-            	port = PSEUDO_PORT_ICMP;
+                port = PSEUDO_PORT_ICMP;
             }
         }
     }
-    
+
     public NetworkAddressTranslationTable getNATTable() {
-    	return natTable;
+        return natTable;
     }
-    
+
     public boolean eintragExistiert(IpPaket packet) {
-    	int protocol = packet.getProtocol();
-    	int port = (protocol == IpPaket.TCP || protocol == IpPaket.UDP)
-                ? packet.getSegment().getZielPort()
-                : ((IcmpPaket) packet).getIdentifier();
-    	return (natTable.find(port, packet.getSender(), protocol)) == null? false: true;
+        int protocol = packet.getProtocol();
+        int port = (protocol == IpPaket.TCP || protocol == IpPaket.UDP)
+            ? packet.getSegment().getZielPort()
+            : ((IcmpPaket) packet).getIdentifier();
+        return (natTable.find(port, packet.getSender(), protocol)) == null ? false : true;
     }
 }


=====================================
src/main/java/filius/software/system/InternetKnotenBetriebssystem.java
=====================================
@@ -32,6 +32,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 
+import filius.software.clientserver.ServerAnwendung;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -403,13 +404,15 @@ public abstract class InternetKnotenBetriebssystem extends SystemSoftware {
                 + " (InternetKnotenBetriebssystem), entferneSoftware(" + awKlasse + ")");
         printInstallierteAnwendungen(); // DEBUG
         boolean entfernt = false;
-        Iterator it = installierteAnwendung.entrySet().iterator();
-
-        while (it.hasNext() && !entfernt) {
-            if (awKlasse.equals((String) ((Entry) it.next()).getKey())) {
-                it.remove();
-                entfernt = true;
+        Anwendung app = installierteAnwendung.get(awKlasse);
+        if (app != null) {
+            if (app instanceof ServerAnwendung) {
+                ((ServerAnwendung)app).setAktiv(false);
             }
+            app.beenden();
+            installierteAnwendung.remove(awKlasse);
+            LOG.info("Anwendung " + awKlasse + " entfernt.");
+            entfernt = true;
         }
         return entfernt;
     }
@@ -459,6 +462,7 @@ public abstract class InternetKnotenBetriebssystem extends SystemSoftware {
             Anwendung neueAnwendung = (Anwendung) cl.getConstructor().newInstance();
             neueAnwendung.setSystemSoftware(this);
             installierteAnwendung.put(klassenname, neueAnwendung);
+            neueAnwendung.starten();
         } catch (Exception e) {
             LOG.debug("App could not be instantiated. Probably because class could not be found.", e);
             erfolg = false;
@@ -466,23 +470,6 @@ public abstract class InternetKnotenBetriebssystem extends SystemSoftware {
         return erfolg;
     }
 
-    public boolean deinstalliereAnwendung(String anwendungsName) {
-        LOG.trace("INVOKED (" + this.hashCode() + ") " + getClass()
-                + " (InternetKnotenBetriebssystem), deinstalliereAnwendung(" + anwendungsName + ")");
-        printInstallierteAnwendungen(); // DEBUG
-        Anwendung anwendung;
-
-        if (anwendungsName == null)
-            return false;
-        anwendung = (Anwendung) installierteAnwendung.get(anwendungsName);
-        if (anwendung == null) {
-            return false;
-        } else {
-            installierteAnwendung.remove(anwendung.holeAnwendungsName());
-            return true;
-        }
-    }
-
     /**
      * Methode zur Abfrage aller aktuell installierter Anwendungen
      * 


=====================================
src/main/java/filius/software/system/SwitchFirmware.java
=====================================
@@ -47,7 +47,7 @@ import filius.software.netzzugangsschicht.SwitchPortBeobachter;
 /**
  * Diese Klasse erweitert den Wert der HashMap für die SAT um einen Eintrag für das letzte Update.
  */
-class satEntry {
+class SatEntry {
 
     private Port port;
     private Date letztes_Update;
@@ -81,7 +81,7 @@ public class SwitchFirmware extends SystemSoftware implements I18n {
     /**
      * Die Source Address Tabel (SAT), in der die MAC-Adressen den physischen Anschluessen des Switch zugeordnet werden
      */
-    private ConcurrentHashMap<String, satEntry> sat = new ConcurrentHashMap<String, satEntry>();
+    private ConcurrentHashMap<String, SatEntry> sat = new ConcurrentHashMap<String, SatEntry>();
 
     /**
      * Liste der Anschlussbeobachter. Sie implementieren die Netzzugangsschicht.
@@ -116,7 +116,7 @@ public class SwitchFirmware extends SystemSoftware implements I18n {
         LOG.trace("INVOKED (" + this.hashCode() + ") " + getClass() + " (SwitchFirmware), starten()");
         SwitchPortBeobachter anschlussBeobachter;
 
-        sat = new ConcurrentHashMap<String, satEntry>();
+        sat = new ConcurrentHashMap<String, SatEntry>();
         switchBeobachter = new LinkedList<SwitchPortBeobachter>();
 
         for (Port anschluss : ((Switch) getKnoten()).getAnschluesse()) {
@@ -183,7 +183,7 @@ public class SwitchFirmware extends SystemSoftware implements I18n {
     public void hinzuSatEintrag(String macAdresse, Port anschluss, Date letztes_Update) {
         LOG.trace("INVOKED (" + this.hashCode() + ") " + getClass() + " (SwitchFirmware), hinzuSatEintrag(" + macAdresse
                 + "," + anschluss + "," + letztes_Update + ")");
-        satEntry eintrag = new satEntry();
+        SatEntry eintrag = new SatEntry();
         eintrag.setPort(anschluss);
         eintrag.hinzuLetztesUpdate(letztes_Update);
         sat.put(macAdresse, eintrag);


=====================================
src/main/java/filius/software/system/SystemSoftware.java
=====================================
@@ -41,9 +41,8 @@ import filius.hardware.knoten.Knoten;
  * (Endsysteme und Uebertragungseinheiten) zur Verfuegung stehen muss. <br />
  * Die Klasse ist abstrakt und wird fuer die verschiedenen Stationen unterschiedlich implementiert.
  */
- at SuppressWarnings("serial")
 public abstract class SystemSoftware extends Observable implements Serializable {
-    private static Logger LOG = LoggerFactory.getLogger(SystemSoftware.class);
+    private static final Logger LOG = LoggerFactory.getLogger(SystemSoftware.class);
 
     /** Die Hardware, auf der diese Systemsoftware laeuft. */
     private Knoten hardware;
@@ -107,6 +106,7 @@ public abstract class SystemSoftware extends Observable implements Serializable
      * 
      * @deprecated Use firePropertyChanged based on the {@link PropertyChangeSupport} mechanism instead.
      */
+    @Deprecated
     public void benachrichtigeBeobacher(Object o) {
         LOG.trace("INVOKED (" + this.hashCode() + ") " + getClass() + " (SystemSoftware), benachrichtigeBeobachter(" + o
                 + ")");


=====================================
src/main/java/filius/software/transportschicht/Segment.java
=====================================
@@ -28,7 +28,7 @@ package filius.software.transportschicht;
 import filius.software.ProtocolDataUnit;
 
 @SuppressWarnings("serial")
-public class Segment extends ProtocolDataUnit {
+public abstract class Segment extends ProtocolDataUnit {
 
     private int quellPort;
     private int zielPort;
@@ -66,4 +66,13 @@ public class Segment extends ProtocolDataUnit {
     public void setZielPort(int zielPort) {
         this.zielPort = zielPort;
     }
+
+    public abstract Segment clone();
+
+    public void copySegmentAttributes(Segment segment) {
+        daten = segment.daten;
+        quellPort = segment.quellPort;
+        zielPort = segment.zielPort;
+        pruefSumme = segment.pruefSumme;
+    }
 }


=====================================
src/main/java/filius/software/transportschicht/Socket.java
=====================================
@@ -138,8 +138,6 @@ public abstract class Socket implements SocketSchnittstelle, I18n {
      * Der Konstruktor ist <b> nicht blockierend</b>.
      * 
      * @param betriebssystem
-     * @param zielAdresse
-     * @param zielPort
      * @throws VerbindungsException
      */
     public Socket(InternetKnotenBetriebssystem betriebssystem, int lokalerPort, int transportProtokoll)


=====================================
src/main/java/filius/software/transportschicht/TcpSegment.java
=====================================
@@ -148,6 +148,24 @@ public class TcpSegment extends Segment implements Serializable {
     public void setWindow(int window) {
         this.window = window;
     }
+
+    @Override
+    public TcpSegment clone() {
+        TcpSegment clone = new TcpSegment();
+        clone.ack = ack;
+        clone.ackNummer = ackNummer;
+        clone.dataOffset = dataOffset;
+        clone.seqNummer = seqNummer;
+        clone.urg = urg;
+        clone.psh = psh;
+        clone.rst = rst;
+        clone.syn = syn;
+        clone.fin = fin;
+        clone.window = window;
+        clone.urgentPointer = urgentPointer;
+        clone.copySegmentAttributes(this);
+        return clone;
+    }
     
     public String toString() {
     	return "[" + "src=" + getQuellPort() + ", " + "dest=" + getZielPort() + ", " + "seq=" + seqNummer + ", " + "ack=" + ackNummer + ", " 


=====================================
src/main/java/filius/software/transportschicht/UDPSocket.java
=====================================
@@ -43,7 +43,7 @@ public class UDPSocket extends Socket {
     private static Logger LOG = LoggerFactory.getLogger(UDPSocket.class);
 
     /** Liste eingehender Segmente */
-    private LinkedList<UdpSegment> puffer = new LinkedList<UdpSegment>();
+    private final LinkedList<UdpSegment> puffer = new LinkedList<UdpSegment>();
 
     /**
      * Ob der Socket verbunden ist, d. h. Aufruf von verbinden() war erfolgreich und Socket wurde noch nicht durch
@@ -93,8 +93,6 @@ public class UDPSocket extends Socket {
      * 
      * @param betriebssystem
      * @param lokalerPort
-     * @param zielAdresse
-     * @param zielPort
      * @throws VerbindungsException
      */
     public UDPSocket(InternetKnotenBetriebssystem betriebssystem, int lokalerPort) throws VerbindungsException {
@@ -110,7 +108,7 @@ public class UDPSocket extends Socket {
      */
     @Override
     public void hinzufuegen(String startIp, int startPort, Segment segment) {
-        LOG.trace("UDP data received from " + startIp + ":" + startPort + ", data: " + segment);
+        LOG.debug("UDP data received from " + startIp + ":" + startPort + ", data: " + segment);
         zielIp = startIp;
         zielPort = startPort;
 
@@ -139,6 +137,7 @@ public class UDPSocket extends Socket {
                 }
             }
             if (puffer.size() >= 1) {
+                LOG.debug("UDP data received (local port {})", lokalerPort);
                 segment = (UdpSegment) puffer.removeFirst();
                 return segment.getDaten();
             } else {


=====================================
src/main/java/filius/software/transportschicht/UdpSegment.java
=====================================
@@ -40,6 +40,14 @@ public class UdpSegment extends Segment implements Serializable {
     public void setLaenge(int laenge) {
         this.laenge = laenge;
     }
+
+    @Override
+    public UdpSegment clone() {
+        UdpSegment clone = new UdpSegment();
+        clone.laenge = laenge;
+        clone.copySegmentAttributes(this);
+        return clone;
+    }
     
     public String toString() {
     	return "[" + "src=" + getQuellPort() + ", " + "dest=" + getZielPort() + ", " + "length=" + laenge + ", " 


=====================================
src/main/java/filius/software/vermittlungsschicht/IpPaket.java
=====================================
@@ -76,7 +76,9 @@ public class IpPaket extends ProtocolDataUnit implements Cloneable {
         clone.ttl = ttl;
         clone.empfaenger = empfaenger;
         clone.sender = sender;
-        clone.data = data;
+        if (null != data) {
+            clone.data = data.clone();
+        }
     }
 
     public String getEmpfaenger() {


=====================================
src/main/java/filius/software/www/WebBrowser.java
=====================================
@@ -1,9 +1,9 @@
 /*
  ** 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): 
+ **     members (2006-2007):
  **         André Asschoff, Johannes Bade, Carsten Dittich, Thomas Gerding,
  **         Nadja Haßler, Ernst Johannes Klebert, Michell Weyer
  **     supervisors:
@@ -14,22 +14,18 @@
  ** 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.www;
 
-import java.io.BufferedReader;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStreamReader;
+import java.io.*;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.nio.charset.Charset;
@@ -61,14 +57,14 @@ import filius.software.transportschicht.TCPSocket;
  * </ol>
  * Diese Methoden haben keinen Rueckgabewert und blockieren auch nicht. Die vom Server gelieferten Daten werden an den
  * Beobachter als HTTPNachricht weitergegeben.
- * 
+ *
  */
 public class WebBrowser extends ClientAnwendung implements I18n {
     private static Logger LOG = LoggerFactory.getLogger(WebBrowser.class);
 
     private static final int ABRUF_HTML = 1, ABRUF_IMG = 2;
 
-    private LinkedList<String> bilddateien = new LinkedList<String>();
+    private final LinkedList<String> bilddateien = new LinkedList<String>();
 
     private String host;
 
@@ -84,12 +80,25 @@ public class WebBrowser extends ClientAnwendung implements I18n {
             ausfuehren("closeConnection", new Object[0]);
         }
 
-        ausfuehren("initConnection", new Object[] { url });
-        ausfuehren("retrieveWebpage", new Object[] { url, post });
+        clearImageCache();
+
+        ausfuehren("initConnection", new Object[]{url});
+        ausfuehren("retrieveWebpage", new Object[]{url, post});
         ausfuehren("retrieveImages", new Object[0]);
         ausfuehren("closeConnection", new Object[0]);
     }
 
+    private void clearImageCache() {
+        synchronized (bilddateien) {
+            for (String bild : bilddateien) {
+                String cachedImage = getBrowserCachePath(bild);
+                new File(cachedImage).delete();
+            }
+            LOG.debug("image cache of browser with {} files cleared", bilddateien.size());
+            bilddateien.clear();
+        }
+    }
+
     void initConnection(URL url) {
         if (url.getHost() != null && !url.getHost().equals("")) {
             host = url.getHost();
@@ -162,11 +171,6 @@ public class WebBrowser extends ClientAnwendung implements I18n {
         return host;
     }
 
-    public void starten() {
-        super.starten();
-        bilddateien = new LinkedList<String>();
-    }
-
     /**
      * liest eine reale Textdatei vom Format .txt ein. Diese befinden sich im Ordner /config
      */
@@ -214,7 +218,7 @@ public class WebBrowser extends ClientAnwendung implements I18n {
     /**
      * Methode zur Verarbeitung von IMG-Tags. Mit einem Parser werden IMG-Tags im uebergebenen Quelltext gesucht. Alle
      * Bilddateien werden in eine Liste geschrieben.
-     * 
+     *
      * @param quelltext
      * @param host
      */
@@ -223,7 +227,7 @@ public class WebBrowser extends ClientAnwendung implements I18n {
                 + " (WebBrowser), verarbeiteIMGTags(" + quelltext + "," + host + ")");
 
         Parser parser = Parser.createParser(quelltext, null);
-        TagFindingVisitor nodeVisitor = new TagFindingVisitor(new String[] { "img" });
+        TagFindingVisitor nodeVisitor = new TagFindingVisitor(new String[]{"img"});
         try {
             parser.visitAllNodesWith(nodeVisitor);
             Node[] nodes = nodeVisitor.getTags(0);
@@ -264,13 +268,8 @@ public class WebBrowser extends ClientAnwendung implements I18n {
                                         || HTTPNachricht.IMAGE_GIF.equalsIgnoreCase(contentType)
                                         || HTTPNachricht.IMAGE_JPG.equalsIgnoreCase(contentType)
                                         || HTTPNachricht.IMAGE_PNG.equalsIgnoreCase(contentType)) {
-                                    synchronized (bilddateien) {
-                                        if (bilddateien.size() > 0) {
-                                            dateipfad = bilddateien.removeFirst();
-                                            Base64.decodeToFile(response.getDaten(),
-                                                    Information.getInformation().getTempPfad() + dateipfad);
-                                        }
-                                    }
+                                    Base64.decodeToFile(response.getDaten(),
+                                            getBrowserCachePath(dateipfad));
                                     benachrichtigeBeobachter();
                                 }
                             }
@@ -285,6 +284,19 @@ public class WebBrowser extends ClientAnwendung implements I18n {
         }
     }
 
+    private String getBrowserCachePath(String filename) {
+        return getBrowserCacheDirectory() + filename;
+    }
+
+    public String getBrowserCacheDirectory() {
+        File cacheDir = new File(Information.getInformation().getTempPfad() + getSystemSoftware().primaryMACAddress());
+        if (!cacheDir.exists()) {
+            boolean success = cacheDir.mkdir();
+            LOG.debug("Created temp directory '{}' with result: {}", cacheDir, success);
+        }
+        return cacheDir.getAbsolutePath() + File.separator;
+    }
+
     void closeConnection() {
         if (socket != null) {
             socket.schliessen();


=====================================
src/main/resources/config/filius.ini
=====================================
@@ -54,3 +54,10 @@ old-exchange-dialog=0
 
 # If the hardware component NAT Gateway / Home Router is available.
 # gateway=0
+
+# Change the terminal font size.
+# Default font size is 11.
+# Recommended is up to 14 if required. Some commands might break visualization.
+# Font size larger than 14 will definitely break the terminal visualization.
+# Allowed values are 10 - 20.
+# terminal-font-size=14


=====================================
src/test/java/filius/software/dhcp/DHCPClientTest.java
=====================================
@@ -11,6 +11,8 @@ import static org.mockito.Mockito.when;
 
 import java.util.Arrays;
 
+import filius.hardware.knoten.Rechner;
+import filius.software.system.InternetKnotenBetriebssystem;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.InjectMocks;
@@ -31,6 +33,8 @@ public class DHCPClientTest {
     @Mock
     private ARP arpMock;
     private long defaultSocketTimeoutMillis = 100;
+    @Mock
+    private InternetKnotenBetriebssystem betriebssystemMock;
 
     @Before
     public void initMocks() {
@@ -74,7 +78,7 @@ public class DHCPClientTest {
         assertThat(config.getIpAddress(), is(offeredIpAddress));
         assertThat(config.getDnsServer(), is(dnsServer));
         assertThat(config.getSubnetMask(), is(subnetMask));
-        assertThat(config.getRouter(), is(router));
+        assertThat(config.getGateway(), is(router));
         assertThat(config.getDhcpServer(), is(serverIdentifier));
     }
 
@@ -82,6 +86,7 @@ public class DHCPClientTest {
     public void testDiscover_NoResponse() throws Exception {
         String clientMacAddress = "01:23:45:67:89:AB";
         when(socketMock.empfangen(anyLong())).thenReturn(null);
+        when(betriebssystemMock.getKnoten()).thenReturn(new Rechner());
 
         dhcpClient.discover(socketMock, clientMacAddress, defaultSocketTimeoutMillis);
     }
@@ -136,7 +141,7 @@ public class DHCPClientTest {
         assertThat(config.getIpAddress(), is(offeredIpAddress));
         assertThat(config.getDnsServer(), is(dnsServer));
         assertThat(config.getSubnetMask(), is(subnetMask));
-        assertThat(config.getRouter(), is(router));
+        assertThat(config.getGateway(), is(router));
         assertThat(config.getDhcpServer(), is(serverIdentifier));
     }
 
@@ -154,6 +159,7 @@ public class DHCPClientTest {
                     dnsServer, serverIdentifier).toString();
         }
         when(socketMock.empfangen(anyLong())).thenReturn(messages[0], Arrays.copyOfRange(messages, 1, messages.length));
+        when(betriebssystemMock.getKnoten()).thenReturn(new Rechner());
 
         dhcpClient.discover(socketMock, clientMacAddress, defaultSocketTimeoutMillis);
     }
@@ -220,6 +226,7 @@ public class DHCPClientTest {
                     .createAckMessage("aa:aa:aa:aa:aa:aa", config.getIpAddress(), config.getDhcpServer()).toString();
         }
         when(socketMock.empfangen(anyLong())).thenReturn(messages[0], Arrays.copyOfRange(messages, 1, messages.length));
+        when(betriebssystemMock.getKnoten()).thenReturn(new Rechner());
 
         dhcpClient.request(socketMock, clientMacAddress, config, defaultSocketTimeoutMillis);
     }
@@ -229,6 +236,7 @@ public class DHCPClientTest {
         String clientMacAddress = "01:23:45:67:89:AB";
         IpConfig config = new IpConfig("1.2.3.4", "5.6.7.8", "255.255.255.128", "9.10.11.12", "13.14.15.16");
         when(socketMock.empfangen(anyLong())).thenReturn(null);
+        when(betriebssystemMock.getKnoten()).thenReturn(new Rechner());
 
         dhcpClient.request(socketMock, clientMacAddress, config, defaultSocketTimeoutMillis);
     }



View it on GitLab: https://salsa.debian.org/java-team/filius/-/commit/f6abad84c331a7defc2eb0cf10c659a6d9346e1b

-- 
View it on GitLab: https://salsa.debian.org/java-team/filius/-/commit/f6abad84c331a7defc2eb0cf10c659a6d9346e1b
You're receiving this email because of your account on salsa.debian.org. Manage all notifications: https://salsa.debian.org/-/profile/notifications | Help: https://salsa.debian.org/help


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-java-commits/attachments/20260610/f6a73b51/attachment.htm>


More information about the pkg-java-commits mailing list