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