From de0b74b1ab6c43ee5c2e4c19c07ae4e20730fbd5 Mon Sep 17 00:00:00 2001
From: Christopher Bohn <bohn@unl.edu>
Date: Wed, 17 Jun 2020 21:53:23 -0500
Subject: [PATCH] Made human entry & display of IP addresses using unsigned
 values

---
 assignment/.gitignore                         |  1 +
 assignment/Makefile                           |  9 +++
 .../socket_chat--patterns-and-testing.md      |  2 +-
 .../edu/unl/cse/csce361/socket_chat/Chat.java | 69 ++++++++++++++++---
 4 files changed, 70 insertions(+), 11 deletions(-)
 create mode 100644 assignment/.gitignore
 create mode 100644 assignment/Makefile

diff --git a/assignment/.gitignore b/assignment/.gitignore
new file mode 100644
index 0000000..2d19fc7
--- /dev/null
+++ b/assignment/.gitignore
@@ -0,0 +1 @@
+*.html
diff --git a/assignment/Makefile b/assignment/Makefile
new file mode 100644
index 0000000..0df9cec
--- /dev/null
+++ b/assignment/Makefile
@@ -0,0 +1,9 @@
+ASSIGNMENTS		= $(wildcard *.md)
+ASSIGNMENT_HTML	= $(ASSIGNMENTS:%.md=%.html)
+
+all: $(ASSIGNMENT_HTML)
+
+%.html: %.md
+	pandoc -o $@ $<
+	sed "s/’/'/g" $@ | sed "s/‘/'/g" | sed 's/”/"/g' | sed 's/“/"/g' > temp
+	mv temp $@
diff --git a/assignment/socket_chat--patterns-and-testing.md b/assignment/socket_chat--patterns-and-testing.md
index fd6df5b..6c38999 100644
--- a/assignment/socket_chat--patterns-and-testing.md
+++ b/assignment/socket_chat--patterns-and-testing.md
@@ -127,7 +127,7 @@ feel for how the program works.
         chatters
     -   When launching SocketChat, both chatters should select the option to be
         the client
-    -   IP address: `-127.93.-91.26` <!--`129.93.165.26`-->, Port: `361NN`,
+    -   IP address: <!--`-127.93.-91.26`--> `129.93.165.26`, Port: `361NN`,
         where *NN* is your team number
 -   The two chatters alternate turns sending Strings to each other over the
     socket
diff --git a/src/main/java/edu/unl/cse/csce361/socket_chat/Chat.java b/src/main/java/edu/unl/cse/csce361/socket_chat/Chat.java
index 478514a..95e3f6d 100644
--- a/src/main/java/edu/unl/cse/csce361/socket_chat/Chat.java
+++ b/src/main/java/edu/unl/cse/csce361/socket_chat/Chat.java
@@ -21,6 +21,15 @@ public class Chat {
         socket = null;
     }
 
+    /**
+     * Provides a test hook to test that the program terminates.
+     *
+     * @param exitCode the code passed to the shell indicating (ab)normal termination
+     */
+    protected void exit(int exitCode) {
+        System.exit(exitCode);
+    }
+
     /**
      * Overrides the system's default Locale.
      *
@@ -90,9 +99,10 @@ public class Chat {
      */
     private Socket connectAsServer(Scanner userInput) throws IOException {
         byte[] address = InetAddress.getLocalHost().getAddress();
+        short[] humanReadableAddress = signedToUnsignedAddress(address);
         // "Host address: ..."
         System.out.println(MessageFormat.format(bundle.getString("connection.info.hostAddress.0.1.2.3"),
-                address[0], address[1], address[2], address[3]));
+                humanReadableAddress[0], humanReadableAddress[1], humanReadableAddress[2], humanReadableAddress[3]));
         int port;
         ServerSocket serverSocket;
         do {
@@ -119,9 +129,10 @@ public class Chat {
      */
     private Socket connectAsClient(Scanner userInput) throws IOException {
         byte[] address = getRemoteHostAddress(userInput);
+        short[] humanReadableAddress = signedToUnsignedAddress(address);
         // "Enter port host is opening at ..."
         String prompt = MessageFormat.format(bundle.getString("connection.prompt.getHostPort.0.1.2.3"),
-                address[0], address[1], address[2], address[3]);
+                humanReadableAddress[0], humanReadableAddress[1], humanReadableAddress[2], humanReadableAddress[3]);
         int port = getPort(prompt, userInput);
         Socket socket = null;
         int attemptCount = 0;
@@ -161,7 +172,7 @@ public class Chat {
     private byte[] getRemoteHostAddress(Scanner userInput) {
         // This assumes IPv4. Probably a good assumption.
         boolean haveGoodAddress = false;
-        byte[] address = new byte[4];
+        short[] address = new short[4];
         while (!haveGoodAddress) {
             // "Enter IP address of host <##.##.##.##>:"
             System.out.print(bundle.getString("connection.prompt.getHostAddress") + " ");
@@ -170,7 +181,7 @@ public class Chat {
                 String[] tokens = addressString.split("\\.");
                 if (tokens.length == 4) {
                     for (int i = 0; i < 4; i++) {
-                        address[i] = Byte.parseByte(tokens[i]);
+                        address[i] = Short.parseShort(tokens[i]);
                     }
                     haveGoodAddress = true;
                 } else {
@@ -179,9 +190,10 @@ public class Chat {
                             addressString));
                     haveGoodAddress = false;
                 }
-            } catch (NumberFormatException nfException) {
+            } catch (NumberFormatException ignored) {
                 // "The IP address should be exactly as reported to the host user."
                 System.out.println(bundle.getString("connection.error.badNumberInAddress"));
+                /*
                 String message = nfException.getMessage();
                 // "Value out of range. Value"
                 if (message.startsWith(bundle.getString("exception.numberFormat.startOfValueOutOfRangeMessage"))) {
@@ -193,10 +205,11 @@ public class Chat {
                                 "connection.error.userAttemptedUnsignedByte.0.1"), value, value - 256));
                     }
                 }
+                */
                 haveGoodAddress = false;
             }
         }
-        return address;
+        return unsignedToSignedAddress(address);
     }
 
     /**
@@ -234,6 +247,46 @@ public class Chat {
         return port;
     }
 
+    /**
+     * Utility function necessary because Java does not have unsigned integer types. Converts from the signed bytes
+     * that Java uses for IP address fields and mimics unsigned values that humans are accustomed to.
+     *
+     * @param signedAddress IP address fields in the range -128..127
+     * @return IP address fields in the range 0..255
+     */
+    private short[] signedToUnsignedAddress(byte[] signedAddress) {
+        short offset = -2 * Byte.MIN_VALUE;
+        short[] unsignedAddress = new short[signedAddress.length];
+        for (int i = 0; i < signedAddress.length; i++) {
+            if (signedAddress[i] >= 0) {
+                unsignedAddress[i] = signedAddress[i];
+            } else {
+                unsignedAddress[i] = (short) (offset + signedAddress[i]);
+            }
+        }
+        return unsignedAddress;
+    }
+
+    /**
+     * Utility function necessary because Java does not have unsigned integer types. Converts from the unsigned values
+     * that humans are accustomed to and converts them to signed bytes that Java uses for IP address fields.
+     *
+     * @param unsignedAddress IP address fields in the range 0..255
+     * @return IP address fields in the range -128..127
+     */
+    private byte[] unsignedToSignedAddress(short[] unsignedAddress) {
+        short offset = -2 * Byte.MIN_VALUE;
+        byte[] signedAddress = new byte[unsignedAddress.length];
+        for (int i = 0; i < unsignedAddress.length; i++) {
+            if (unsignedAddress[i] <= Byte.MAX_VALUE) {
+                signedAddress[i] = (byte) unsignedAddress[i];
+            } else {
+                signedAddress[i] = (byte) (unsignedAddress[i] - offset);
+            }
+        }
+        return signedAddress;
+    }
+
     /*
      *  THESE METHODS PERFORM CHAT AFTER CONNECTION IS SET UP
      */
@@ -363,10 +416,6 @@ public class Chat {
         return true;
     }
 
-    protected void exit(int exitCode) {
-        System.exit(exitCode);
-    }
-
     private String encipher(String plaintext) {
         String ciphertext = plaintext;      // Replace this with a call to cipherBehavior.encipher(plaintext)
         return ciphertext;
-- 
GitLab