--- /dev/null
+Start een sessie
+$ sudo bash setup.sh
+$ bash bouw.sh
+$ bash run.sh
+
+Start een nieuwe sessie
+$ cd ~/tt2015/a4/tcp/server
+$ make
+$ sudo java Main
+
+Start een nieuwe sessie
+$ cd ~/tt2015/a4/tcp/adapter
+$ sudo python listener.py
--- /dev/null
+#!/usr/bin/python
+from sender import Sender
+import sys
+import socket
+
+PORT = 8888
+
+if __name__ == "__main__":
+ serverPort = 10000
+ if len(sys.argv) > 1:
+ serverPort = int(sys.argv[1])
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ s.bind(('', PORT))
+ s.listen(1)
+ print 'Listening on port {}'.format(PORT)
+ conn, addr = s.accept()
+ print 'Connected by {}'.format(addr)
+ sender = None
+ seqnr = 100
+ sender = Sender(serverIP="127.0.0.1", networkInterface="lo", isLocal=True, serverPort=serverPort, waitTime=1, isVerbose=0)
+ response = ''
+ while True:
+ data = conn.recv(1024)
+ if not data:
+ break
+ data = data.strip()
+ print 'input: ' + data
+ if data == 'Listen?':
+ sender = Sender(serverIP="127.0.0.1", networkInterface="lo", isLocal=True, serverPort=serverPort, waitTime=1, isVerbose=0)
+ response = ''
+ elif data == 'SYN?':
+ seqnr = 100
+ print 'S: {}'.format(seqnr)
+ response = sender.sendInput('S', seqnr, seqnr)
+ elif data == 'ACK?':
+ seqnr += 1
+ print 'A: {}'.format(seqnr)
+ response = sender.sendInput('A', seqnr, sender.lastSeqReceived + 1)
+ elif data == 'FINACK?':
+ seqnr += 1
+ print 'FA: {}'.format(seqnr)
+ response = sender.sendInput("FA", seqnr, sender.lastSeqReceived + 1)
+ elif data == 'FIN?':
+ seqnr += 1
+ print 'F: {}'.format(seqnr)
+ response = sender.sendInput("F", seqnr, sender.lastSeqReceived + 1)
+ elif data == 'RST?':
+ seqnr += 1
+ print 'RP: {}'.format(seqnr)
+ response = sender.sendInput("RP", seqnr, 0)
+ sender.sendReset()
+ elif data == 'DAT?':
+ print 'DAT: {} sending: a'.format(seqnr)
+ response = sender.sendInput('A', seqnr, sender.lastSeqReceived + 1)
+ response = sender.sendInput('PA', seqnr, sender.lastSeqReceived + 1, data='a\n')
+ seqnr += 2
+ if response:
+ print 'response: {}'.format(response)
+ if response == 'Timeout':
+ print 'data: {} - TIMEOUT!'.format(data)
+ conn.send('TIMEOUT!\n')
+ elif response[0] == 'A' or response[0] == 'PA':
+ print 'data: {} - ACK!'.format(data)
+ conn.send('ACK!\n')
+ elif response[0] == 'R':
+ print 'data: {} - RST!'.format(data)
+ conn.send('RST!\n')
+ elif response[0] == 'SA':
+ print 'data: {} - SYNACK!'.format(data)
+ conn.send('SYNACK!\n')
+ else:
+ print 'data: {}'.format(data)
+
+ print 'closed'
+ conn.close()
+ exit()
--- /dev/null
+#!/usr/bin/python
+from sender import Sender
+import sys
+import socket
+
+PORT = 8888
+
+if __name__ == "__main__":
+ serverPort = 10000
+ if len(sys.argv) > 1:
+ serverPort = int(sys.argv[1])
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ s.bind(('', PORT))
+ s.listen(1)
+ print 'Listening on port {}'.format(PORT)
+ conn, addr = s.accept()
+ print 'Connected by {}'.format(addr)
+ print 'Initiating connection to EchoServer at port {}...'.format(serverPort)
+ sender = Sender(serverIP="127.0.0.1", networkInterface="lo", isLocal=True, serverPort=serverPort, waitTime=1, isVerbose=0)
+ seqnr = 0
+ response = ''
+ data = ''
+ while True:
+ print 'waiting for data'
+ done = False
+ while not done:
+ d = conn.recv(1)
+ if not d:
+ break
+ if d != '\n':
+ data += d
+ if d == '\n':
+ done = True
+ print 'received: {}'.format(data)
+ if data == 'RES':
+ print 'resetting the SUT...'
+ sender = Sender(serverIP="127.0.0.1", networkInterface="lo", isLocal=True, serverPort=serverPort, waitTime=1, isVerbose=0)
+ data = ''
+ continue
+ elif data == 'SYN':
+ seqnr = 100
+ print 'S: {}'.format(seqnr)
+ response = sender.sendInput('S', seqnr, seqnr)
+ elif data == 'ACK':
+ response = 'Timeout'
+ if sender.lastSeqReceived != None:
+ seqnr += 1
+ print 'A: {}'.format(seqnr)
+ response = sender.sendInput('A', seqnr, sender.lastSeqReceived + 1)
+ elif data == 'DAT':
+ response = 'Timeout'
+ if sender.lastSeqReceived != None:
+ seqnr += 1
+ print 'DAT: {} sending: a'.format(seqnr)
+ response = sender.sendInput('PA', seqnr, sender.lastSeqReceived + 1, 'a')
+ elif data == 'RST':
+ response = 'Timeout'
+ if sender.lastSeqReceived != None:
+ seqnr += 1
+ print 'RP: {}'.format(seqnr)
+ response = sender.sendInput("RP", seqnr, 0)
+ sender.sendReset()
+ elif data == 'FIN':
+ response = 'Timeout'
+ if sender.lastSeqReceived != None:
+ seqnr += 1
+ print 'F: {}'.format(seqnr)
+ response = sender.sendInput("FA", seqnr, sender.lastSeqReceived + 1)
+ else:
+ print 'INVALID INPUT!: {}'.format(repr(data))
+ break
+
+ if response == 'Timeout':
+ data = 'TO'
+ elif response[0] == 'A':
+ data = 'ACK'
+ elif response[0] == 'PA':
+ data = 'DATA'
+ elif response[0] == 'R':
+ data = 'RST'
+ elif response[0] == 'SA':
+ data = 'SYN-ACK'
+ else:
+ data = 'ERR'
+
+ print 'RESPONSE: '+data
+ conn.send('{}\n'.format(data))
+ print 'sent...'
+ data = ''
+ print 'closed'
+ conn.close()
+ exit()
--- /dev/null
+from scapy.all import *\r
+\r
+verbose = 0\r
+\r
+def vb_print(msg):\r
+ global verbose\r
+ if verbose == 1:\r
+ print msg\r
+\r
+# the sender sends packets with configurable parameters to a server and retrieves responses\r
+class Sender:\r
+ # information on the SUT\r
+ def __init__(self, serverIP, serverPort=8000,\r
+ networkInterface="lo", isLocal=True, senderPortMinimum=20000,\r
+ senderPortMaximum=40000, portNumberFile="sn.txt",\r
+ isVerbose=0, waitTime=1):\r
+ \r
+ \r
+ # file where the last sender port used is stored\r
+ self.portNumberFile = portNumberFile;\r
+ \r
+ # when choosing a fresh port, a new port is chosen\r
+ # within boundaries defined by the parameters below\r
+ self.senderPortMinimum = senderPortMinimum\r
+ self.senderPortMaximum = senderPortMaximum\r
+ \r
+ # data on sender and server needed to send packets \r
+ self.serverIP = serverIP\r
+ self.serverPort = serverPort\r
+ self.networkInterface = networkInterface\r
+ self.senderPort = self.getNextPort()\r
+ self.isLocal = isLocal\r
+ \r
+ # time to wait for a response from the server before concluding a timeout\r
+ self.waitTime = waitTime\r
+ \r
+ # verbose or not\r
+ self.isVerbose = isVerbose\r
+ \r
+ # variables added so you can easily test the last system response\r
+ self.lastSeqReceived = None\r
+ self.lastAckReceived = None\r
+ self.isTimeout = None\r
+ self.lastFlagsReceived = None\r
+ self.lastDataReceived = None\r
+ \r
+\r
+ # chooses a new port to send packets from\r
+ def refreshNetworkPort(self):\r
+ vb_print("previous local port: " + str(self.senderPort))\r
+ self.senderPort = self.getNextPort()\r
+ vb_print("next local port: " + str(self.senderPort) + "\n")\r
+ return self.senderPort\r
+\r
+ # gets a new port number, an increment of the old within the specified limits. Uses a file.\r
+ def getNextPort(self):\r
+ f = open(self.portNumberFile, "a+")\r
+ f.seek(0)\r
+ line = f.readline()\r
+ if line == '' or int(line) < self.senderPortMinimum:\r
+ networkPort = self.senderPortMinimum\r
+ else:\r
+ networkPort = (int(line) + 1) % self.senderPortMaximum\r
+ f.closed\r
+ f = open(self.portNumberFile, "w")\r
+ f.write(str(networkPort))\r
+ f.closed\r
+ return networkPort\r
+\r
+ # send a packet onto the network with the given parameters, and return the response packet\r
+ # in case of a timeout, returns None, otherwise, returns the tuple (flags, seqNo, ackNo)\r
+ def sendPacket(self, flagsSet, seqNr, ackNr, data = None):\r
+ packet = self.createPacket(flagsSet, seqNr, ackNr, data)\r
+ # consider adding the parameter: iface="ethx" if you don't receive a response. Also consider increasing the wait time\r
+ scapyResponse = sr1(packet, timeout=self.waitTime, verbose=self.isVerbose)\r
+ if scapyResponse is not None:\r
+ # scapyResponse.show() \r
+ # ^^ in case you want to show the packet content \r
+ # here is what you store from every packet response\r
+ if Raw not in scapyResponse: \r
+ response = (self.intToFlags(scapyResponse[TCP].flags), scapyResponse[TCP].seq, scapyResponse[TCP].ack, None)\r
+ else: \r
+ response = (self.intToFlags(scapyResponse[TCP].flags), scapyResponse[TCP].seq, scapyResponse[TCP].ack, scapyResponse[Raw].load)\r
+ else:\r
+ response = "Timeout"\r
+ return response\r
+ \r
+ # function that creates packet from data strings/integers \r
+ # data is used for attaching data to the packet\r
+ def createPacket(self, tcpFlagsSet, seqNr, ackNr, data=None):\r
+ vb_print("" + tcpFlagsSet + " " + str(seqNr) + " " + str(ackNr))\r
+ pIP = IP(dst=self.serverIP, flags="DF")\r
+ pTCP = TCP(sport=self.senderPort,\r
+ dport=self.serverPort,\r
+ seq=seqNr,\r
+ ack=ackNr,\r
+ flags=tcpFlagsSet)\r
+ if data is None:\r
+ p = pIP / pTCP\r
+ else:\r
+ p = pIP / pTCP / Raw(load=data)\r
+ return p\r
+ \r
+ # check whether there is a 1 at the given bit-position of the integer\r
+ def checkForFlag(self, x, flagPosition):\r
+ if x & 2 ** flagPosition == 0:\r
+ return False\r
+ else:\r
+ return True\r
+\r
+ # the flags-parameter of a network packets is returned as an int, this function converts\r
+ # it to a string (such as "FA" if the Fin-flag and Ack-flag have been set)\r
+ def intToFlags(self, x):\r
+ result = ""\r
+ if self.checkForFlag(x, 0):\r
+ result = result + "F"\r
+ if self.checkForFlag(x, 1):\r
+ result = result + "S"\r
+ if self.checkForFlag(x, 2):\r
+ result = result + "R"\r
+ if self.checkForFlag(x, 3):\r
+ result = result + "P"\r
+ if self.checkForFlag(x, 4):\r
+ result = result + "A"\r
+ return result\r
+ \r
+ # sends input over the network to the server\r
+ def sendInput(self, input1, seqNr, ackNr, data = None):\r
+ conf.sniff_promisc = False\r
+ conf.iface = self.networkInterface\r
+ if self.isLocal == True:\r
+ conf.L3socket = L3RawSocket # if the connection is local/localhost, use l3 raw sockets\r
+ vb_print("sending: "+ str((input1, seqNr, ackNr, data)))\r
+ response = self.sendPacket(input1, seqNr, ackNr, data)\r
+ \r
+ # updating sender state variables\r
+ if response != "Timeout":\r
+ (self.lastFlagsReceived, self.lastSeqReceived, self.lastAckReceived, self.lastDataReceived) = response\r
+ self.isTimeout = False\r
+ else: \r
+ self.isTimeout = True\r
+ \r
+ # printing response\r
+ vb_print("received: "+ str(response))\r
+ return response\r
+\r
+ # resets the connection by changing the port number. On some OSes (Win 8) upon hitting a certain number of\r
+ # connections opened on a port, packets are sent to close down connections. \r
+ def sendReset(self):\r
+ self.refreshNetworkPort()\r
--- /dev/null
+#!/bin/bash -x
+javac -d . -sourcepath tester/ -cp ":lib/automata-parent.jar:lib/learnlib-parent.jar" tester/learner/*.java
--- /dev/null
+#!/bin/bash -x
+java -cp ":lib/automata-parent.jar:lib/learnlib-parent.jar" learner.Main
--- /dev/null
+#!/bin/bash -x
+rm -r learner *.{pdf,dot}
--- /dev/null
+import java.net.Socket;\r
+import java.net.SocketException;\r
+\r
+/**\r
+ * Default connection handler. Very basic, does not read or send anything.\r
+ */\r
+public class DefaultHandler implements Runnable {\r
+ private Socket socket;\r
+\r
+ public DefaultHandler(Socket socket) {\r
+ this.socket = socket;\r
+ try {\r
+ socket.setTcpNoDelay(false);\r
+ } catch (SocketException e) {\r
+ // TODO Auto-generated catch block\r
+ e.printStackTrace();\r
+ }\r
+ new Thread(this).start();\r
+ }\r
+\r
+ public void run() {\r
+ {\r
+ // here you can customize operations you want to test though it's not necessary\r
+ System.out.println("new socket opening on " + socket.getLocalPort());\r
+ while (!socket.isOutputShutdown()) {\r
+ try {\r
+ Thread.sleep(100);\r
+ } catch (InterruptedException e) {\r
+ // TODO Auto-generated catch block\r
+ e.printStackTrace();\r
+ }\r
+ }\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+import java.io.InputStreamReader;\r
+import java.io.OutputStreamWriter;\r
+import java.net.Socket;\r
+import java.net.SocketException;\r
+\r
+/**\r
+ * Connection echo handler. Everything it receives is sent back.\r
+ */\r
+public class EchoHandler implements Runnable {\r
+ private Socket socket;\r
+\r
+ public EchoHandler(Socket socket) {\r
+ this.socket = socket;\r
+ try {\r
+ socket.setTcpNoDelay(false);\r
+ } catch (SocketException e) {\r
+ // TODO Auto-generated catch block\r
+ e.printStackTrace();\r
+ }\r
+ new Thread(this).start();\r
+ }\r
+\r
+ public void run() {\r
+ {\r
+ try {\r
+ System.out.println("new socket opening on "\r
+ + socket.getLocalPort());\r
+ InputStreamReader in = new InputStreamReader(\r
+ socket.getInputStream());\r
+ OutputStreamWriter out = new OutputStreamWriter(socket.getOutputStream());\r
+ int s;\r
+ while(((s=in.read()) != -1)) {\r
+ out.append((char)s);\r
+ out.flush();\r
+ System.out.print((char)s);\r
+ }\r
+ System.out.println();\r
+ System.out.println("Closing handler");\r
+ } catch (Exception e) {\r
+ // TODO Auto-generated catch block\r
+ e.printStackTrace();\r
+ }\r
+\r
+ }\r
+ }\r
+}\r
--- /dev/null
+import java.net.InetAddress;\r
+\r
+// Run the TCPServer on the the port testPort\r
+public class Main {\r
+ private static final int DEFAULT_PORT = 10000;\r
+ private static final String DEFAULT_ADDRESS = "127.0.0.1";\r
+\r
+ /**\r
+ * Run the program with arguments to set a custom port and address, see the comments in the code\r
+ * @param args\r
+ * @throws Exception\r
+ */\r
+ public static void main(String[] args) throws Exception { \r
+ System.setProperty("java.net.preferIPv4Stack", "true"); // force ipv4\r
+ int port;\r
+ String address;\r
+ if (args.length == 0) {\r
+ // no arguments: default port and address\r
+ port = DEFAULT_PORT;\r
+ address = DEFAULT_ADDRESS;\r
+ } else if (args.length == 1) {\r
+ // one argument for port, default address\r
+ port = Integer.valueOf(args[0]);\r
+ address = DEFAULT_ADDRESS;\r
+ } else if (args.length == 2) {\r
+ // two arguments for port and address\r
+ // for example, call it like 'java Main 10000 127.0.0.1'\r
+ port = Integer.valueOf(args[0]);\r
+ address = args[1];\r
+ } else {\r
+ return;\r
+ }\r
+ TCPServer server = new TCPServer(port, InetAddress.getByName(address));\r
+ \r
+ // comment this for the default handler, otherwise the echo server is used\r
+ server.setHandlerType("echo");\r
+ \r
+ server.handleConnections();\r
+ }\r
+}\r
--- /dev/null
+all: Main.class
+
+%.class: %.java
+ javac $<
+
+clean:
+ $(RM) *.class
--- /dev/null
+import static java.lang.System.out;\r
+\r
+import java.net.InetAddress;\r
+import java.net.NetworkInterface;\r
+import java.net.SocketException;\r
+import java.util.Collections;\r
+import java.util.Enumeration;\r
+\r
+// this utility displays information on addresses and ports, you don't need to use it\r
+public class NetHelper \r
+{\r
+ public static void main(String args[]) throws SocketException {\r
+ Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();\r
+ \r
+ for (NetworkInterface netIf : Collections.list(nets)) {\r
+ out.printf("Display name: %s\n", netIf.getDisplayName());\r
+ out.printf("Name: %s\n", netIf.getName());\r
+ displayInterfaceInformation(netIf);\r
+ displaySubInterfaces(netIf);\r
+ out.printf("\n");\r
+ }\r
+ }\r
+ \r
+ public static NetworkInterface getNetworkInterface(String netName) {\r
+ NetworkInterface netIntf = null;\r
+ try {\r
+ for (Enumeration<NetworkInterface> en = NetworkInterface\r
+ .getNetworkInterfaces(); en.hasMoreElements();) {\r
+ NetworkInterface intf = en.nextElement();\r
+ if (intf.getName().compareToIgnoreCase(netName) == 0) {\r
+ netIntf = intf;\r
+ break;\r
+ }\r
+ }\r
+ } catch (SocketException e) {\r
+ System.out\r
+ .println("Socket Exception failed to find internet addresses!");\r
+ e.printStackTrace();\r
+ System.exit(0);\r
+ }\r
+ return netIntf;\r
+ }\r
+\r
+ public static InetAddress getFirstNonLocalHost(NetworkInterface netIntf) {\r
+ Enumeration<InetAddress> hosts = netIntf.getInetAddresses();\r
+ InetAddress address = null;\r
+ while (hosts.hasMoreElements()) {\r
+ InetAddress host = hosts.nextElement();\r
+ if (!host.isLinkLocalAddress() && !host.isLoopbackAddress()) {\r
+ address = host;\r
+ break;\r
+ }\r
+ }\r
+ return address;\r
+ }\r
+\r
+ \r
+ \r
+ static String getMac(NetworkInterface netint) throws SocketException {\r
+ byte[] mac = netint.getHardwareAddress();\r
+ String rez = "null";\r
+ if(mac != null) {\r
+ StringBuilder sb = new StringBuilder();\r
+ for (int i = 0; i < mac.length; i++) {\r
+ sb.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? "-" : "")); \r
+ }\r
+ rez = sb.toString();\r
+ }\r
+ return rez;\r
+ //System.out.println(sb.toString());\r
+ }\r
+ \r
+ static void displayInterfaceInformation(NetworkInterface netint) throws SocketException {\r
+ out.printf("Display name: %s\n", netint.getDisplayName());\r
+ out.printf("Name: %s\n", netint.getName());\r
+ out.printf("MAC: %s\n", getMac(netint));\r
+ Enumeration<InetAddress> inetAddresses = netint.getInetAddresses();\r
+ for (InetAddress inetAddress : Collections.list(inetAddresses)) {\r
+ out.printf("InetAddress: %s\n", inetAddress);\r
+ out.println("LOCAL:" + Boolean.toString(inetAddress.isLoopbackAddress() || inetAddress.isLinkLocalAddress()));\r
+ }\r
+ out.printf("\n");\r
+ }\r
+\r
+ static void displaySubInterfaces(NetworkInterface netIf) throws SocketException {\r
+ Enumeration<NetworkInterface> subIfs = netIf.getSubInterfaces();\r
+ \r
+ for (NetworkInterface subIf : Collections.list(subIfs)) {\r
+ out.printf("\tSub Interface Display name: %s\n", subIf.getDisplayName());\r
+ out.printf("\tSub Interface Name: %s\n", subIf.getName());\r
+ displayInterfaceInformation(subIf);\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+import java.io.IOException;\r
+import java.net.InetAddress;\r
+import java.net.ServerSocket;\r
+import java.net.Socket;\r
+import java.net.UnknownHostException;\r
+\r
+/**\r
+ * A simple TCP server. Listens for connections, and for each incoming connection,\r
+ * it creates a 'handler' (either echo handler or default handler) which controls\r
+ * that connection\r
+ */\r
+public class TCPServer implements Runnable {\r
+ public ServerSocket server;\r
+ public Socket socket;\r
+ private String handler;\r
+ \r
+ public TCPServer(int port, InetAddress address) {\r
+ try {\r
+ server = new ServerSocket(port, 0, address);\r
+ server.setReuseAddress(true);\r
+ System.out.println("Listening on:\n"\r
+ + server.getInetAddress().toString() + "\nport: "\r
+ + server.getLocalPort());\r
+ } catch (IOException e) {\r
+ e.printStackTrace();\r
+ }\r
+ }\r
+ \r
+ public TCPServer(int port) throws UnknownHostException {\r
+ this(port,InetAddress.getLocalHost());\r
+ }\r
+ \r
+ public void setHandlerType(String handlerClass) {\r
+ this.handler = handlerClass;\r
+ }\r
+ \r
+ private void startHandler(Socket socket) {\r
+ System.out.println("Starting handler '"+ ((handler!=null) ? handler : "default") + "'");\r
+ if("echo".equalsIgnoreCase(handler)) {\r
+ new EchoHandler(socket);\r
+ } else {\r
+ new DefaultHandler(socket);\r
+ }\r
+ }\r
+\r
+ public void handleConnections() {\r
+ Thread thread = new Thread(this);\r
+ thread.start();\r
+ }\r
+\r
+ @Override\r
+ public void run() {\r
+ System.out.println("Waiting for client messages...");\r
+\r
+ // accept all requests for connections\r
+ while (true) {\r
+ try {\r
+ socket = server.accept();\r
+ startHandler(socket);\r
+ } catch (IOException e) {\r
+ //e.printStackTrace();\r
+ System.err.println("Closed socket");\r
+ break;\r
+ }\r
+ }\r
+ }\r
+}\r
--- /dev/null
+#!/bin/sh
+iptables -A OUTPUT -p tcp --tcp-flags PSH PSH -j ACCEPT
+iptables -A OUTPUT -p tcp --tcp-flags RST RST -j DROP
--- /dev/null
+package learner;
+
+import net.automatalib.words.Word;
+
+/**
+ * Contains the full input for which non-determinism was observed, as well as the full new output
+ * and the (possibly shorter) old output with which it disagrees
+ *
+ * @author Ramon Janssen
+ */
+public class CacheInconsistencyException extends RuntimeException {
+ private final Word oldOutput, newOutput, input;
+
+ public CacheInconsistencyException(Word input, Word oldOutput, Word newOutput) {
+ this.input = input;
+ this.oldOutput = oldOutput;
+ this.newOutput = newOutput;
+ }
+
+ public CacheInconsistencyException(String message, Word input, Word oldOutput, Word newOutput) {
+ super(message);
+ this.input = input;
+ this.oldOutput = oldOutput;
+ this.newOutput = newOutput;
+ }
+
+
+ /**
+ * The shortest cached output word which does not correspond with the new output
+ * @return
+ */
+ public Word getOldOutput() {
+ return this.oldOutput;
+ }
+
+ /**
+ * The full new output word
+ * @return
+ */
+ public Word getNewOutput() {
+ return this.newOutput;
+ }
+
+ /**
+ * The shortest sublist of the input word which still shows non-determinism
+ * @return
+ */
+ public Word getShortestInconsistentInput() {
+ int indexOfInconsistency = 0;
+ while (oldOutput.getSymbol(indexOfInconsistency).equals(newOutput.getSymbol(indexOfInconsistency))) {
+ indexOfInconsistency ++;
+ }
+ return this.input.subWord(0, indexOfInconsistency);
+ }
+
+ @Override
+ public String toString() {
+ return "Non-determinism detected\nfull input:\n" + this.input + "\nfull new output:\n" + this.newOutput + "\nold output:\n" + this.oldOutput;
+ }
+}
--- /dev/null
+package learner;
+
+import de.learnlib.api.SUL;
+import de.learnlib.api.SULException;
+
+/**
+ * Example of a three-state system, hard-coded.
+ *
+ * @author Ramon Janssen
+ */
+public class ExampleSUL implements SUL<String, String> {
+ private enum State{s0,s1,s2};
+ private State currentState;
+ private static boolean VERBOSE = false;
+
+ @Override
+ public void pre() {
+ // add any code here that should be run at the beginning of every 'session',
+ // i.e. put the system in its initial state
+ if (VERBOSE) {
+ System.out.println("Starting SUL");
+ }
+ currentState = State.s0;
+ }
+
+ @Override
+ public void post() {
+ // add any code here that should be run at the end of every 'session'
+ if (VERBOSE) {
+ System.out.println("Shutting down SUL");
+ }
+ }
+
+ @Override
+ public String step(String input) throws SULException {
+ State previousState = this.currentState;
+ String output = makeTransition(input);
+ State nextState = this.currentState;
+ if (VERBOSE) {
+ System.out.println(previousState + " --" + input + "/" + output + "-> " + nextState);
+ }
+ return output;
+ }
+
+ /**
+ * The behaviour of the SUL. It takes one input, and returns an output. It now
+ * contains a hardcoded state-machine (so the result is easy to check). To learn
+ * an external program/system, connect this method to the SUL (e.g. via sockets
+ * or stdin/stdout) and make it perform an actual input, and retrieve an actual
+ * output.
+ * @param input
+ * @return
+ */
+ public String makeTransition(String input) {
+ switch (currentState) {
+ case s0:
+ switch(input) {
+ case "a":
+ currentState = State.s1;
+ return "x";
+ case "b":
+ currentState = State.s2;
+ return "y";
+ case "c":
+ return "z";
+ }
+ case s1:
+ switch(input) {
+ case "a":
+ return "z";
+ case "b":
+ currentState = State.s2;
+ return "y";
+ case "c":
+ return "z";
+ }
+ case s2:
+ switch(input) {
+ case "a":
+ return "z";
+ case "b":
+ currentState = State.s0;
+ return "y";
+ case "c":
+ return "z";
+ }
+ }
+ throw new SULException(new IllegalArgumentException("Argument '" + input + "' was not handled"));
+ }
+}
--- /dev/null
+package learner;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.InetAddress;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Random;
+
+import net.automatalib.automata.transout.MealyMachine;
+import net.automatalib.commons.dotutil.DOT;
+import net.automatalib.graphs.concepts.GraphViewable;
+import net.automatalib.util.graphs.dot.GraphDOT;
+import net.automatalib.words.Alphabet;
+import net.automatalib.words.Word;
+import net.automatalib.words.impl.SimpleAlphabet;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+
+import de.learnlib.acex.analyzers.AcexAnalyzers;
+import de.learnlib.algorithms.kv.mealy.KearnsVaziraniMealy;
+import de.learnlib.algorithms.lstargeneric.ce.ObservationTableCEXHandlers;
+import de.learnlib.algorithms.lstargeneric.closing.ClosingStrategies;
+import de.learnlib.algorithms.lstargeneric.mealy.ExtensibleLStarMealy;
+import de.learnlib.algorithms.ttt.mealy.TTTLearnerMealy;
+import de.learnlib.api.EquivalenceOracle;
+import de.learnlib.api.LearningAlgorithm;
+import de.learnlib.api.MembershipOracle.MealyMembershipOracle;
+import de.learnlib.api.SUL;
+import de.learnlib.eqtests.basic.WMethodEQOracle;
+import de.learnlib.eqtests.basic.WpMethodEQOracle;
+import de.learnlib.eqtests.basic.mealy.RandomWalkEQOracle;
+import de.learnlib.experiments.Experiment.MealyExperiment;
+import de.learnlib.oracles.DefaultQuery;
+import de.learnlib.oracles.ResetCounterSUL;
+import de.learnlib.oracles.SULOracle;
+import de.learnlib.oracles.SymbolCounterSUL;
+import de.learnlib.statistics.Counter;
+
+/**
+ * General learning testing framework. The most important parameters are the input alphabet and the SUL (The
+ * first two static attributes). Other settings can also be configured.
+ *
+ * Based on the learner experiment setup of Joshua Moerman, https://gitlab.science.ru.nl/moerman/Learnlib-Experiments
+ *
+ * @author Ramon Janssen
+ */
+public class Main {
+ //*****************//
+ // SUL information //
+ //*****************//
+ // Defines the input alphabet, adapt for your socket (you can even use other types than string, if you
+ // change the generic-values, e.g. make your SUL of type SUL<Integer, Float> for int-input and float-output
+ private static final Alphabet<String> inputAlphabet =
+ new SimpleAlphabet<String>(ImmutableSet.of(
+ "SYN", "ACK",
+ "DAT", "RST", "FIN"));
+ // There are two SULs predefined, an example (see ExampleSul.java) and a socket SUL which connects to the SUL over socket
+ private static final SULType sulType = SULType.Socket;
+ public enum SULType { Example, Socket }
+ // For SULs over socket, the socket address/port can be set here
+ private static final InetAddress socketIp = InetAddress.getLoopbackAddress();
+ private static final int socketPort = 8888;
+ private static final boolean printNewLineAfterEveryInput = true; // print newlines in the socket connection
+ private static final String resetCmd = "RES"; // the command to send over socket to reset sut
+
+ //*******************//
+ // Learning settings //
+ //*******************//
+ // file for writing the resulting .dot-file and .pdf-file (extensions are added automatically)
+ private static final String OUTPUT_FILENAME = "learnedModel";
+ // the learning and testing algorithms. LStar is the basic algorithm, TTT performs much faster
+ // but is a bit more inaccurate and produces more intermediate hypotheses, so test well)
+ private static final LearningMethod learningAlgorithm = LearningMethod.LStar;
+ public enum LearningMethod { LStar, RivestSchapire, TTT, KearnsVazirani }
+ // Random walk is the simplest, but performs badly on large models: the chance of hitting a
+ // erroneous long trace is very small
+ private static final TestingMethod testMethod = TestingMethod.RandomWalk;
+ public enum TestingMethod { RandomWalk, WMethod, WpMethod }
+ // for random walk, the chance to do a reset after an input and the number of
+ // inputs to test before accepting a hypothesis
+ private static final double chanceOfResetting = 0.1;
+ private static final int numberOfSymbols = 100;
+ // Simple experiments produce very little feedback, controlled produces feedback after
+ // every hypotheses and are better suited to adjust by programming
+ private static final boolean runControlledExperiment = true;
+ // For controlled experiments only: store every hypotheses as a file. Useful for 'debugging'
+ // if the learner does not terminate (hint: the TTT-algorithm produces many hypotheses).
+ private static final boolean saveAllHypotheses = false;
+
+ public static void main(String [] args) throws IOException {
+ // Load the actual SUL-class, depending on which SUL-type is set at the top of this file
+ // You can also program an own SUL-class if you extend SUL<String,String> (or SUL<S,T> in
+ // general, with S and T the input and output types - you'll have to change some of the
+ // code below)
+ SUL<String,String> sul;
+ switch (sulType) {
+ case Example:
+ sul = new ExampleSUL();
+ break;
+ case Socket:
+ sul = new SocketSUL(socketIp, socketPort, printNewLineAfterEveryInput, resetCmd);
+ break;
+ default:
+ throw new RuntimeException("No SUL-type defined");
+ }
+
+ // Wrap the SUL in a detector for non-determinism
+ sul = new NonDeterminismCheckingSUL<String,String>(sul);
+ // Wrap the SUL in counters for symbols/resets, so that we can record some statistics
+ SymbolCounterSUL<String, String> symbolCounterSul = new SymbolCounterSUL<>("symbol counter", sul);
+ ResetCounterSUL<String, String> resetCounterSul = new ResetCounterSUL<>("reset counter", symbolCounterSul);
+ Counter nrSymbols = symbolCounterSul.getStatisticalData(), nrResets = resetCounterSul.getStatisticalData();
+ // we should use the sul only through those wrappers
+ sul = resetCounterSul;
+ // Most testing/learning-algorithms want a membership-oracle instead of a SUL directly
+ MealyMembershipOracle<String,String> sulOracle = new SULOracle<>(sul);
+
+ // Choosing an equivalence oracle
+ EquivalenceOracle<MealyMachine<?, String, ?, String>, String, Word<String>> eqOracle = null;
+ switch (testMethod){
+ // simplest method, but doesn't perform well in practice, especially for large models
+ case RandomWalk:
+ eqOracle = new RandomWalkEQOracle<>(chanceOfResetting, numberOfSymbols, true, new Random(123456l), sul);
+ break;
+ // Other methods are somewhat smarter than random testing: state coverage, trying to distinguish states, etc.
+ case WMethod:
+ eqOracle = new WMethodEQOracle.MealyWMethodEQOracle<>(3, sulOracle);
+ break;
+ case WpMethod:
+ eqOracle = new WpMethodEQOracle.MealyWpMethodEQOracle<>(3, sulOracle);
+ break;
+ default:
+ throw new RuntimeException("No test oracle selected!");
+ }
+
+ // Choosing a learner
+ LearningAlgorithm<MealyMachine<?, String, ?, String>, String, Word<String>> learner = null;
+ switch (learningAlgorithm){
+ case LStar:
+ learner = new ExtensibleLStarMealy<>(inputAlphabet, sulOracle, Lists.<Word<String>>newArrayList(), ObservationTableCEXHandlers.CLASSIC_LSTAR, ClosingStrategies.CLOSE_SHORTEST);
+ break;
+ case RivestSchapire:
+ learner = new ExtensibleLStarMealy<>(inputAlphabet, sulOracle, Lists.<Word<String>>newArrayList(), ObservationTableCEXHandlers.RIVEST_SCHAPIRE, ClosingStrategies.CLOSE_SHORTEST);
+ break;
+ case TTT:
+ learner = new TTTLearnerMealy<>(inputAlphabet, sulOracle, AcexAnalyzers.LINEAR_FWD);
+ break;
+ case KearnsVazirani:
+ learner = new KearnsVaziraniMealy<>(inputAlphabet, sulOracle, false, AcexAnalyzers.LINEAR_FWD);
+ break;
+ default:
+ throw new RuntimeException("No learner selected");
+ }
+
+ // Running the actual experiments!
+ if (runControlledExperiment) {
+ runControlledExperiment(learner, eqOracle, nrSymbols, nrResets, inputAlphabet);
+ } else {
+ runSimpleExperiment(learner, eqOracle, inputAlphabet);
+ }
+ }
+
+ /**
+ * Simple example of running a learning experiment
+ * @param learner Learning algorithm, wrapping the SUL
+ * @param eqOracle Testing algorithm, wrapping the SUL
+ * @param alphabet Input alphabet
+ * @throws IOException if the result cannot be written
+ */
+ public static void runSimpleExperiment(
+ LearningAlgorithm<MealyMachine<?, String, ?, String>, String, Word<String>> learner,
+ EquivalenceOracle<MealyMachine<?, String, ?, String>, String, Word<String>> eqOracle,
+ Alphabet<String> alphabet) throws IOException {
+ MealyExperiment<String, String> experiment = new MealyExperiment<String, String>(learner, eqOracle, alphabet);
+ experiment.run();
+ System.out.println("Ran " + experiment.getRounds().getCount() + " rounds");
+ produceOutput(OUTPUT_FILENAME, experiment.getFinalHypothesis(), alphabet, true);
+ }
+
+ /**
+ * More detailed example of running a learning experiment. Starts learning, and then loops testing,
+ * and if counterexamples are found, refining again. Also prints some statistics about the experiment
+ * @param learner learner Learning algorithm, wrapping the SUL
+ * @param eqOracle Testing algorithm, wrapping the SUL
+ * @param nrSymbols A counter for the number of symbols that have been sent to the SUL (for statistics)
+ * @param nrResets A counter for the number of resets that have been sent to the SUL (for statistics)
+ * @param alphabet Input alphabet
+ * @throws IOException
+ */
+ public static void runControlledExperiment(
+ LearningAlgorithm<MealyMachine<?, String, ?, String>, String, Word<String>> learner,
+ EquivalenceOracle<MealyMachine<?, String, ?, String>, String, Word<String>> eqOracle,
+ Counter nrSymbols, Counter nrResets,
+ Alphabet<String> alphabet) throws IOException {
+
+ // prepare some counters for printing statistics
+ int stage = 0;
+ long lastNrResetsValue = 0, lastNrSymbolsValue = 0;
+
+ // start the actual learning
+ learner.startLearning();
+
+ while(true) {
+ // store hypothesis as file
+ if(saveAllHypotheses) {
+ String outputFilename = "hyp." + stage + ".obf.dot";
+ PrintWriter output = new PrintWriter(outputFilename);
+ produceOutput(outputFilename, learner.getHypothesisModel(), alphabet, false);
+ output.close();
+ }
+
+ // Print statistics
+ System.out.println(stage + ": " + Calendar.getInstance().getTime());
+ // Log number of queries/symbols
+ System.out.println("Hypothesis size: " + learner.getHypothesisModel().size() + " states");
+ long roundResets = nrResets.getCount() - lastNrResetsValue, roundSymbols = nrSymbols.getCount() - lastNrSymbolsValue;
+ System.out.println("learning queries/symbols: " + nrResets.getCount() + "/" + nrSymbols.getCount()
+ + "(" + roundResets + "/" + roundSymbols + " this learning round)");
+ lastNrResetsValue = nrResets.getCount();
+ lastNrSymbolsValue = nrSymbols.getCount();
+
+ // Search for CE
+ DefaultQuery<String, Word<String>> ce = eqOracle.findCounterExample(learner.getHypothesisModel(), alphabet);
+
+ // Log number of queries/symbols
+ roundResets = nrResets.getCount() - lastNrResetsValue;
+ roundSymbols = nrSymbols.getCount() - lastNrSymbolsValue;
+ System.out.println("testing queries/symbols: " + nrResets.getCount() + "/" + nrSymbols.getCount()
+ + "(" + roundResets + "/" + roundSymbols + " this testing round)");
+ lastNrResetsValue = nrResets.getCount();
+ lastNrSymbolsValue = nrSymbols.getCount();
+
+ if(ce == null) {
+ // No counterexample found, stop learning
+ System.out.println("\nFinished learning!");
+ produceOutput(OUTPUT_FILENAME, learner.getHypothesisModel(), alphabet, true);
+ break;
+ } else {
+ // Counterexample found, rinse and repeat
+ System.out.println();
+ stage++;
+ learner.refineHypothesis(ce);
+ }
+ }
+ }
+
+ /**
+ * Produces a dot-file and a PDF (if graphviz is installed)
+ * @param fileName filename without extension - will be used for the .dot and .pdf
+ * @param model
+ * @param alphabet
+ * @param verboseError whether to print an error explaing that you need graphviz
+ * @throws FileNotFoundException
+ * @throws IOException
+ */
+ public static void produceOutput(String fileName, MealyMachine<?,String,?,String> model, Alphabet<String> alphabet, boolean verboseError) throws FileNotFoundException, IOException {
+ GraphDOT.write(model, alphabet, new PrintWriter(OUTPUT_FILENAME + ".dot"));
+ try {
+ DOT.runDOT(new File(OUTPUT_FILENAME + ".dot"), "pdf", new File(OUTPUT_FILENAME + ".pdf"));
+ } catch (Exception e) {
+ if (verboseError) {
+ System.err.println("Warning: Install graphviz to convert dot-files to PDF");
+ System.err.println(e.getMessage());
+ }
+ }
+ }
+}
--- /dev/null
+package learner;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import de.learnlib.api.SUL;
+import de.learnlib.api.SULException;
+
+/**
+ * SUL-wrapper to check for non-determinism, by use of an observation tree.
+ *
+ * @author Ramon Janssen
+ *
+ * @param <I>
+ * @param <O>
+ */
+public class NonDeterminismCheckingSUL<I,O> implements SUL<I,O> {
+ private final SUL<I,O> sul;
+ private final ObservationTree<I,O> root = new ObservationTree<I,O>();
+ private final List<I> inputs = new ArrayList<>();
+ private final List<O> outputs = new ArrayList<>();
+
+ public NonDeterminismCheckingSUL(SUL<I,O> sul) {
+ this.sul = sul;
+ }
+
+ @Override
+ public void post() {
+ sul.post();
+ // check for non-determinism: crashes if outputs are inconsistent with previous ones
+ root.addObservation(inputs, outputs);
+ inputs.clear();
+ outputs.clear();
+ }
+
+ @Override
+ public void pre() {
+ sul.pre();
+ }
+
+ @Override
+ public O step(I input) throws SULException {
+ O result = sul.step(input);
+ inputs.add(input);
+ outputs.add(result);
+ return result;
+ }
+}
--- /dev/null
+package learner;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import net.automatalib.words.Word;
+
+/**
+ * @author Ramon Janssen
+ *
+ * @param <I> the input type of the observations
+ * @param <O> the output type of the observations
+ */
+public class ObservationTree<I,O> {
+ private final ObservationTree<I,O> parent;
+ private final I parentInput;
+ private final O parentOutput;
+ private final Map<I, ObservationTree<I,O>> children;
+ private final Map<I, O> outputs;
+
+ public ObservationTree() {
+ this(null, null, null);
+ }
+
+ private ObservationTree(ObservationTree<I,O> parent, I parentInput, O parentOutput) {
+ this.children = new HashMap<>();
+ this.outputs = new HashMap<>();
+ this.parent = parent;
+ this.parentInput = parentInput;
+ this.parentOutput = parentOutput;
+ }
+
+ /**
+ * @return The outputs observed from the root of the tree until this node
+ */
+ private List<O> getOutputChain() {
+ if (this.parent == null) {
+ return new LinkedList<O>();
+ } else {
+ List<O> parentChain = this.parent.getOutputChain();
+ parentChain.add(parentOutput);
+ return parentChain;
+ }
+ }
+
+ private List<I> getInputChain() {
+ if (this.parent == null) {
+ return new LinkedList<I>();
+ } else {
+ List<I> parentChain = this.parent.getInputChain();
+ parentChain.add(this.parentInput);
+ return parentChain;
+ }
+ }
+
+ /**
+ * Add one input and output symbol and traverse the tree to the next node
+ * @param input
+ * @param output
+ * @return the next node
+ * @throws InconsistencyException
+ */
+ public ObservationTree<I,O> addObservation(I input, O output) throws CacheInconsistencyException {
+ O previousOutput = this.outputs.get(input);
+ boolean createNewBranch = previousOutput == null;
+ if (createNewBranch) {
+ // input hasn't been queried before, make a new branch for it and traverse
+ this.outputs.put(input, output);
+ ObservationTree<I,O> child = new ObservationTree<I,O>(this, input, output);
+ this.children.put(input, child);
+ return child;
+ } else if (!previousOutput.equals(output)) {
+ // input is inconsistent with previous observations, throw exception
+ List<O> oldOutputChain = this.children.get(input).getOutputChain();
+ List<O> newOutputChain = this.getOutputChain();
+ List<I> inputChain = this.getInputChain();
+ newOutputChain.add(output);
+ throw new CacheInconsistencyException(toWord(inputChain), toWord(oldOutputChain), toWord(newOutputChain));
+ } else {
+ // input is consistent with previous observations, just traverse
+ return this.children.get(input);
+ }
+ }
+
+ /**
+ * Add Observation to the tree
+ * @param inputs
+ * @param outputs
+ * @throws CacheInconsistencyException Inconsistency between new and stored observations
+ */
+ public void addObservation(Word<I> inputs, Word<O> outputs) throws CacheInconsistencyException {
+ addObservation(inputs.asList(), outputs.asList());
+ }
+
+
+ public void addObservation(List<I> inputs, List<O> outputs) throws CacheInconsistencyException {
+ if (inputs.isEmpty() && outputs.isEmpty()) {
+ return;
+ } else if (inputs.isEmpty() || outputs.isEmpty()) {
+ throw new RuntimeException("Input and output words should have the same length:\n" + inputs + "\n" + outputs);
+ } else {
+ I firstInput = inputs.get(0);
+ O firstOutput = outputs.get(0);
+ try {
+ this.addObservation(firstInput, firstOutput)
+ .addObservation(inputs.subList(1, inputs.size()), outputs.subList(1, outputs.size()));
+ } catch (CacheInconsistencyException e) {
+ throw new CacheInconsistencyException(toWord(inputs), e.getOldOutput(), toWord(outputs));
+ }
+ }
+ }
+
+ public static<T> Word<T> toWord(List<T> symbolList) {
+ return Word.fromList(symbolList);
+ }
+}
--- /dev/null
+package learner;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+
+import de.learnlib.api.SUL;
+import de.learnlib.api.SULException;
+
+/**
+ * Socket interface to connect to an SUT/test adapter over TCP.
+ *
+ * As an example, type into a unix terminal "nc -vl {ip} {port}" (where {ip} and
+ * {port} are the chosen values), and run this socketSUL. You can now control the
+ * SUL through the terminal.
+ * @author Ramon Janssen
+ */
+public class SocketSUL implements SUL<String, String>, AutoCloseable {
+ private final BufferedReader SULoutput;
+ private final PrintWriter SULinput;
+ private final Socket socket;
+ private final boolean extraNewLine;
+ private final String resetCmd;
+
+ /**
+ * Socket-interface for SUTs. Connects to a SUT (or test-adapter)
+ * @param ip the ip-address
+ * @param port the tcp-port
+ * @param extraNewLine whether to print a newline after every input to the SUT
+ * @param resetCmd the command to send for resetting the SUT
+ * @throws UnknownHostException
+ * @throws IOException
+ */
+ public SocketSUL(InetAddress ip, int port, boolean extraNewLine, String resetCmd) throws UnknownHostException, IOException {
+ this.socket = new Socket(ip, port);
+ this.SULoutput = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+ this.SULinput = new PrintWriter(socket.getOutputStream(), true);
+ this.extraNewLine = extraNewLine;
+ this.resetCmd = resetCmd;
+ }
+
+ @Override
+ public void post() {
+ if (extraNewLine) {
+ this.SULinput.write(this.resetCmd + System.lineSeparator());
+ } else {
+ this.SULinput.write(this.resetCmd);
+ }
+ this.SULinput.flush();
+ }
+
+ @Override
+ public void pre() {
+
+ }
+
+ @Override
+ public String step(String input) throws SULException {
+ if (extraNewLine) {
+ this.SULinput.write(input + System.lineSeparator());
+ } else {
+ this.SULinput.write(input);
+ }
+ this.SULinput.flush();
+ try {
+ return this.SULoutput.readLine();
+ } catch (IOException e) {
+ throw new SULException(e);
+ }
+ }
+
+ @Override
+ public void close() throws Exception {
+ this.socket.close();
+ }
+}
--- /dev/null
+package learner;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.net.Socket;
+
+
+public class SutSocketWrapper {
+ private Socket sock;
+ private PrintWriter sockout;
+ private BufferedReader sockin;
+ private int run;
+
+ public SutSocketWrapper(int portNumber) {
+
+ try {
+ sock = new Socket("localhost", portNumber);
+
+ /* Call setTcpNoDelay to improve communication performance : */
+
+ sock.setTcpNoDelay(true); // remove unnecessary delay in socket communication!
+
+
+ // make char writer from byte writer which automatically encodes chars using UTF-8 and
+ // automatically flushes the buffer on each println call.
+ sockout = new PrintWriter(new OutputStreamWriter(sock.getOutputStream(), "UTF-8"),true);
+ // make char reader from byte reader which automatically decodes bytes to chars using UTF-8
+ sockin = new BufferedReader(new InputStreamReader(sock.getInputStream(), "UTF-8"));
+
+
+ run=1;
+ } catch (IOException e) {
+ // e.printStackTrace();
+ System.err.println("");
+ System.err.println("\n\nPROBLEM: problem connecting with SUT:\n\n " + e.getMessage() +"\n\n");
+ System.exit(1);
+ }
+ }
+
+
+
+ public String sendInput(String inputStr) {
+ try {
+
+ // Send input to SUT
+ sockout.println(inputStr);
+ sockout.flush();
+
+ // Receive output from SUT
+ String outputStr=sockin.readLine();
+ if (outputStr==null) {
+ System.err.println("");
+ System.err.println("\n\nPROBLEM: problem reading output from SUT: SUT closed connection\n\n " );
+ System.exit(1);
+ }
+
+ return outputStr;
+ } catch (IOException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public void sendReset() {
+
+ // send reset to SUT
+ sockout.println("reset");
+ sockout.flush();
+
+ run=run+1;
+ }
+
+
+
+
+ public void close() {
+ /*
+ try {
+ sockin.close();
+ sockout.close();
+ sock.close();
+ } catch (IOException ex) {
+
+ }
+ */
+ }
+
+
+
+}