diff --git a/src/main/java/slp/SLPProtocol.java b/src/main/java/slp/SLPProtocol.java index 2592f2dcc0e88c53b886d11a659d0bbeab66deea..dce45653439dba874d1f9bac3f002551b85916d9 100644 --- a/src/main/java/slp/SLPProtocol.java +++ b/src/main/java/slp/SLPProtocol.java @@ -2,120 +2,261 @@ package slp; import java.io.IOException; import java.net.InetAddress; +import java.net.Socket; import java.net.SocketTimeoutException; import java.util.HashMap; import java.util.Map; +import java.util.zip.CRC32; +import java.util.zip.Checksum; -import core.Configuration; import core.Msg; +import core.Configuration; import core.Protocol; import phy.PhyConfiguration; +import phy.PhyMsg; import phy.PhyProtocol; import exceptions.*; +import javax.xml.crypto.Data; public class SLPProtocol extends Protocol { - private static final int SLPTIMEOUT = 2000; - private int myID; - private final PhyProtocol phy; - private final boolean isSwitch; - private boolean isRegistered; - private boolean useTimeout; - // Switches map slp id to virtual link - private Map<Integer, PhyConfiguration> systems; - PhyConfiguration phyConfig; - - // Constructor - public SLPProtocol(int id, boolean isSwitch, PhyProtocol proto) throws IWProtocolException { - if(isSwitch == true && id < 5000) { - systems = new HashMap<>(); - } else { - if(SLPRegMsg.validateAddress(id) == false ) - throw new IllegalAddrException(); - this.myID = id; - this.isRegistered = false; - } - this.isSwitch = isSwitch; - this.phy = proto; - } - - /* - * Enable/disable the use of timeout when reading from socket - */ - private void enableTimeout() { - this.useTimeout = true; - } - private void disableTimeout() { - this.useTimeout = false; - } + private static final int SLPTIMEOUT = 2000; + private int myID; + private final PhyProtocol phy; + private final boolean isSwitch; + private boolean isRegistered; + private boolean useTimeout; + // Switches map slp id to virtual link + private Map<Integer, PhyConfiguration> systems; + PhyConfiguration phyConfig; + + + // Constructor + public SLPProtocol(int id, boolean isSwitch, PhyProtocol proto) throws IWProtocolException { + if (isSwitch && id < 5000) { + systems = new HashMap<>(); + } else { + if (SLPRegMsg.validateAddress(id) == false) + throw new IllegalAddrException(); + this.myID = id; + this.isRegistered = false; + } + this.isSwitch = isSwitch; + this.phy = proto; + } + + /* + * Enable/disable the use of timeout when reading from socket + */ + public void enableTimeout() { + this.useTimeout = true; + } + + public void disableTimeout() { + this.useTimeout = false; + } - // Register an end systems - public void register(InetAddress rname, int rp) throws IWProtocolException, IOException { - // Create registration message object - SLPRegMsg reg = new SLPRegMsg(); - // Fill registration message fields - reg.create(Integer.toString(this.myID)); - // Create configuration object - this.phyConfig = new PhyConfiguration(rname, rp); - - /* -- Remove for task 4 -- */ - // Send registration request via phy layer - phy.send(new String(reg.getDataBytes()), this.phyConfig); - SLPMsg in = new SLPMsg(); - ; - Msg inBasic; - try { - // Receive response from phy layer - timeout 2s - inBasic = this.phy.receive(2000); - // Get data from msg object - String sentence = inBasic.getData(); - // Parse response - in = (SLPMsg) in.parse(sentence); - } catch (SocketTimeoutException e) { - System.out.println("No response received"); - throw new RegistrationFailedException(); - }catch (IllegalMsgException e) { - System.out.println("Cannot parse response"); - throw new RegistrationFailedException(); - } - // If any other message than a registration response message was received or - // the registration response indicates failure throw exception - if (!(in instanceof SLPRegResponseMsg) || (((SLPRegResponseMsg)in).getRegResponse() == false)) { - // A registration non-acknowledgement is signaled by throwing an exception - throw new RegistrationFailedException(); - } - /* -- End remove for task 4 -- */ - - this.isRegistered = true; + // Combine setting the Timeouts + public void setTimeout(boolean newTimeout){ + this.useTimeout = newTimeout; } + + // Register an end systems + public void register(InetAddress rname, int rp) throws IWProtocolException, IOException { + + /* ------------ CODE FROM TASK 2 + // Create registration message object + SLPRegMsg reg = new SLPRegMsg(); + // Fill registration message fields + reg.create(Integer.toString(this.myID)); + // Create configuration object + this.phyConfig = new PhyConfiguration(rname, rp); + + phy.send(new String(reg.getDataBytes()), this.phyConfig); + + // Subtask 2: Receive response message, parse it, and inform app + boolean msgRegResponse; + + // Parse message if error occurs throw RegistrationFailedExceoption + try { + SLPMsg msg = new SLPMsg(); + msg = (SLPMsg) msg.parse(phy.receive(SLPTIMEOUT).getData()); + msgRegResponse = ((SLPRegResponseMsg) msg).getRegResponse(); + } catch (IllegalMsgException | SocketTimeoutException e) { + throw new RegistrationFailedException(); + } + + // If RegResponse was true conclude register else throw RegistrationFailedExceoption + if (msgRegResponse) { + this.isRegistered = true; + } else { + throw new RegistrationFailedException(); + } + return; + ------------ CODE FROM TASK 2*/ + + + // Updated registration using timeout + SLPRegMsg reg = new SLPRegMsg(); + // Fill registration message fields + reg.create(Integer.toString(this.myID)); + // Create configuration object + this.phyConfig = new PhyConfiguration(rname, rp); + // Counter for attempting registration + int attempt = 0; + + while (attempt < 3) { + + phy.send(new String(reg.getDataBytes()), this.phyConfig); + + // Receive response message, parse it, and inform app + boolean msgRegResponse = false; + + // Parse message if error occurs printStackTrace + try { + SLPMsg msg = new SLPMsg(); + msg = (SLPMsg) msg.parse(phy.receive(SLPTIMEOUT).getData()); + msgRegResponse = ((SLPRegResponseMsg) msg).getRegResponse(); + } catch (IllegalMsgException | SocketTimeoutException e) { + e.printStackTrace(); + } + + // If RegResponse was true conclude register else increase number of attempts + if (msgRegResponse) { + this.isRegistered = true; + return; + } + attempt++; + } + throw new RegistrationFailedException(); + } - // Create SLPDataMsg object (subtask 3.3) and send + // Create SLPDataMsg object (subtask 3.3) and send // Subtask 2.1 - @Override - public void send(String s, Configuration config) throws IOException, IWProtocolException { - + @Override + public void send(String sentence, Configuration config) throws IOException, IWProtocolException { - } + // Send the message, if the Client has been registered + if (isRegistered) { + SLPDataMsg msg = new SLPDataMsg((SLPConfiguration) config, myID); + msg.create(sentence); + phy.send(new String(msg.getDataBytes()), phyConfig); + } else { + throw new RegistrationFailedException(); + } + } - // Receive message from underlying protocol, parse and process + // Receive message from underlying protocol, parse and process // Subtask 2.2 - @Override - public Msg receive() throws IOException, IWProtocolException { - SLPMsg in = null; + @Override + public Msg receive() throws IOException, IWProtocolException { + SLPMsg respMsg; + Boolean isRunning = true; + // Check if the Client has been registered + if (isRegistered || isSwitch) { + while (isRunning) { + try { + Msg phyMsg; + if(useTimeout){ + phyMsg = phy.receive(SLPTIMEOUT); + } else { + phyMsg = phy.receive(); + } + + // Receive message and parse it + respMsg = new SLPMsg(); + respMsg = (SLPMsg) respMsg.parse(phyMsg.getData()); - return in; - } + /* Is the parsed message a registration message? + If it is and it's a switch, register the Client. */ + if (respMsg instanceof SLPRegMsg) { + if (!isSwitch) { + System.out.println("Client ist already registered -> Discard Message"); + throw new IllegalMsgException(); + } else { + registration((SLPRegMsg) respMsg, phyMsg.getConfiguration()); + return null; + } + } + /* Was the message meant to be sent to client? + Drop it silently, if not. */ + if (!isSwitch && ((SLPDataMsg) respMsg).getReceiverId() != this.myID) { + System.out.println(((SLPDataMsg) respMsg).getReceiverId() + " is someone else. I am " +this.myID); + throw new IllegalReceiveException(); + } + return respMsg; - public void storeAndForward() throws IOException { - while (true) { - forward(); - } - } + } catch (BadChecksumException | IllegalMsgException | RegistrationFailedException | + IllegalReceiveException e) { + e.printStackTrace(); + } catch (SocketTimeoutException e) { + isRunning = false; + } + } + throw new SocketTimeoutException(); + } else { + throw new RegistrationFailedException(); + } - public void forward() throws IOException { - // Subtask 3.2 - } + } + + public void storeAndForward() throws IOException, IWProtocolException { + while (true) { + forward(); + } + } + + public void forward() throws IWProtocolException, IOException { + + // Receive a message and if it was a registration message dont foward it + SLPMsg datMsg = (SLPMsg) this.receive(); + if (datMsg == null) { + return; + } + + // Get the PhyConfig of the receiver and sender by their IDs + PhyConfiguration receiverConfig = this.systems.get(((SLPDataMsg) datMsg).getReceiverId()); + PhyConfiguration senderConfig = this.systems.get(((SLPDataMsg) datMsg).getSenderID()); + + // In case one of the clients isn't registered dont send the message else forwad it to the receiver + if (receiverConfig == null || senderConfig == null) { + System.out.println("Discarding message some clients not registered"); + } else { + System.out.println("Forwarding message: '" + datMsg.getData() + "' with sender: " + ((SLPDataMsg) datMsg).getSenderID() + " and receiver: " + ((SLPDataMsg) datMsg).getReceiverId()); + phy.send(((SLPDataMsg) datMsg).getreceivedMessage(), receiverConfig); + } + + + } + + // Registration Method which is used by the switch to register new Clients to its Hashmap + private void registration(SLPRegMsg regMsg, Configuration config) throws IWProtocolException, IOException { + try { + + SLPRegResponseMsg regResponseMsg = new SLPRegResponseMsg(); + + // Check whether Client is already registered to the ID if not put him into the Hashmap with his PhyConfig + if (this.systems.containsKey(regMsg.getSlpId())) { + regResponseMsg.setRegResponse(false); + } else { + this.systems.put(regMsg.getSlpId(), (PhyConfiguration) config); + regResponseMsg.setRegResponse(true); + System.out.println("Registered: " + regMsg.getSlpId()); + } + + // Create corresponding SLPRegResponseMsg and send it to the Client + regResponseMsg.create(Integer.toString(regMsg.getSlpId())); + phy.send(new String(regResponseMsg.getDataBytes()), config); + + } catch (IllegalMsgException e) { + throw new RegistrationFailedException(); + } + } + + public PhyProtocol getPhy() { + return phy; + } }