diff --git a/central-manager/lib/local/handler.c b/central-manager/lib/local/handler.c index f4f1e3a..b368f99 100644 --- a/central-manager/lib/local/handler.c +++ b/central-manager/lib/local/handler.c @@ -364,7 +364,7 @@ void* manageCtrlTerm(void* THREADABLE_ARGS){ /* 2. Si erreur reception */ if( count <= 0 ) // because of timeout or error - continue; + break; if( count < TERMREQ_LEN ){ send(arg->socket, "\0\0", sizeof(char)*2, 0); diff --git a/command-terminal/commandTerm.jar b/command-terminal/commandTerm.jar index dc9885c..5b9dddf 100644 Binary files a/command-terminal/commandTerm.jar and b/command-terminal/commandTerm.jar differ diff --git a/command-terminal/src/ControlTerminal/ControlTerminal.java b/command-terminal/src/ControlTerminal/ControlTerminal.java new file mode 100644 index 0000000..b0f1765 --- /dev/null +++ b/command-terminal/src/ControlTerminal/ControlTerminal.java @@ -0,0 +1,182 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + +package ControlTerminal; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Scanner; + +import DatagramSocket.AsynchronousDatagramSocket; + +/** + * + * @author lmascaro + */ +public class ControlTerminal { + + private final static int SGCA_MULTICAST_PORT = 4446; + private final static String SCGA_MULTICAST_ADDRESS = "224.0.0.3"; + + /** + * @param args the command line arguments + */ + public static void main(String[] args){ + System.out.println("\033[2J"); + + /* + * Handshake + */ + int port = 0; + String addressString = "0.0.0.0"; + + try { + DatagramSocket socket = new DatagramSocket(); + ByteBuffer buf = ByteBuffer.allocate(21); + buf.clear(); + buf.put((byte)(0x05)); + + DatagramPacket payload = new DatagramPacket(buf.array(),buf.array().length,InetAddress.getByName(SCGA_MULTICAST_ADDRESS),SGCA_MULTICAST_PORT); + socket.send(payload); + + socket.receive(payload); + + buf = ByteBuffer.wrap(payload.getData()); + if(buf.get() == 5){ + System.out.println("--Connection request successful"); + byte address[] = new byte[4]; + buf = buf.get(address,0,4); + InetAddress addressObj = InetAddress.getByAddress(address); + addressString = addressObj.getHostAddress(); + //emulate an unsigned short + char cast = buf.getChar(); + port = (int) cast; + System.out.println("----Address : "+addressString); + System.out.println("----Port : "+port); + } + + } catch ( IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return; + } + + /* + * Opening final socket + */ + try { + //create all objects + AsynchronousDatagramSocket socket = new AsynchronousDatagramSocket(); + PlaneContainer container = new PlaneContainer(); + Printer printer = new Printer(); + Pinger pinger = new Pinger(socket,InetAddress.getByName(addressString),port); + + //bind them + socket.bindContainer(container); + container.bindPrinter(printer); + container.bindSocket(socket); + printer.bindContainer(container); + + + //send first packet + InetAddress SGCAaddress = InetAddress.getByName(addressString); + DatagramPacket p = new DatagramPacket(new byte[13],13,SGCAaddress,port); + socket.send(p); + System.out.println("First packet sent"); + + //send first feedback packet + ByteBuffer buf = ByteBuffer.allocate(27); + buf.put((byte) 0x01); + p = new DatagramPacket(buf.array(),buf.array().length,SGCAaddress,port); + socket.send(p); + System.out.println("Feedback request sent"); + + System.out.println("length: "+"aze".getBytes().length); + + //run Pinger + new Thread(pinger).start(); + + //now we let the objects do the job + Scanner s = new Scanner(System.in); + int planeNumber; + int data; + Plane plane; + ArrayList keys; + byte flags; + while(true){ + + String input = s.nextLine(); + if(input.length() == 0){ + //if empty line, we send a feedback request + buf = ByteBuffer.allocate(27); + buf.put((byte) 0x01); + p = new DatagramPacket(buf.array(),buf.array().length,SGCAaddress,port); + socket.send(p); + System.out.println("Request sent, waiting for response"); + + }else{ + System.out.println("Please enter plane number"); + planeNumber = s.nextInt(); + keys = new ArrayList(container.getMap().keySet()); + plane = container.getMap().get(keys.get(planeNumber-1)); + flags = 0x01; + while(true){ + System.out.println("Enter the information you want to update (1: alt,2:cap,3:speed)"); + data = s.nextInt(); + switch(data){ + case 1: + System.out.println("Enter the new altitude"); + data = s.nextInt(); + plane.setZ(data); + flags = (byte) (flags|0x08); + break; + case 2: + System.out.println("Enter the new cap"); + data = s.nextInt(); + plane.setCap(data); + flags = (byte) (flags|0x02); + break; + case 3: + System.out.println("Enter the new speed"); + data = s.nextInt(); + plane.setSpeed(data); + flags = (byte) (flags|0x04); + break; + } + System.out.println("Do you want to update more data on this plane (y/n)"); + + if(s.next().equals("n")){ + break; + } + } + System.out.println("flags: "+flags); + buf = ByteBuffer.allocate(27); + buf.put(flags); + buf.put(plane.toBytes()); + p = new DatagramPacket(buf.array(),buf.array().length,SGCAaddress,port); + socket.send(p); + System.out.println("Request sent, waiting for response"); + s.nextLine(); + } + + } + + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + +} diff --git a/command-terminal/src/ControlTerminal/InvalidFlagException.java b/command-terminal/src/ControlTerminal/InvalidFlagException.java new file mode 100644 index 0000000..a315a66 --- /dev/null +++ b/command-terminal/src/ControlTerminal/InvalidFlagException.java @@ -0,0 +1,18 @@ +package ControlTerminal; + +public class InvalidFlagException extends Exception { + + /** + * + */ + private static final long serialVersionUID = 1L; + + public InvalidFlagException(){ + super(); + } + + public InvalidFlagException(String message){ + super(message); + } + +} diff --git a/command-terminal/src/ControlTerminal/Pinger.java b/command-terminal/src/ControlTerminal/Pinger.java new file mode 100644 index 0000000..3d8f690 --- /dev/null +++ b/command-terminal/src/ControlTerminal/Pinger.java @@ -0,0 +1,46 @@ +package ControlTerminal; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.InetAddress; +import java.nio.ByteBuffer; + +import DatagramSocket.AsynchronousDatagramSocket; + +public class Pinger implements Runnable{ + + private AsynchronousDatagramSocket socket; + private InetAddress addr; + private int port; + + public Pinger(AsynchronousDatagramSocket socket,InetAddress addr,int port){ + this.socket = socket; + this.addr = addr; + this.port = port; + } + + @Override + public void run() { + DatagramPacket p; + ByteBuffer buf = ByteBuffer.allocate(27); + while(true){ + try { + Thread.sleep(8000); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + p = new DatagramPacket(buf.array(),buf.array().length,this.addr,this.port); + try { + this.socket.send(p); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + + } + +} diff --git a/command-terminal/src/ControlTerminal/Plane.java b/command-terminal/src/ControlTerminal/Plane.java new file mode 100644 index 0000000..a437024 --- /dev/null +++ b/command-terminal/src/ControlTerminal/Plane.java @@ -0,0 +1,125 @@ +package ControlTerminal; + +import java.io.Serializable; +import java.nio.ByteBuffer; + +public class Plane{ + + private String code; + private int x; + private int y; + private int z; + private int cap; + private int speed; + + private boolean isDead; + + public Plane(String code,int x, int y, int z, int cap, int speed){ + this.code = code; + this.x = x; + this.y = y; + this.z = z; + this.cap = cap; + this.speed = speed; + this.isDead = false; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public int getX() { + return x; + } + + public void setX(int x) { + this.x = x; + } + + public int getY() { + return y; + } + + public void setY(int y) { + this.y = y; + } + + public int getZ() { + return z; + } + + public void setZ(int z) { + this.z = z; + } + + public int getCap() { + return cap; + } + + public boolean isDead(){ + return this.isDead; + } + + public void setCap(int cap) { + this.cap = cap; + } + + public int getSpeed() { + return speed; + } + + public void setSpeed(int speed) { + this.speed = speed; + } + + //Die Motherfucker + public void die(){ + this.isDead = true; + } + + public String getLine(int i){ + switch(i){ + case 0: + return "--------------------------------"; + case 1: + if(this.isDead){ + return "\033[4;37;41m Code: "+this.code+"\t\t\t|"; + }else{ + return "\033[4;37;42m Code: "+this.code+"\t\t\t|"; + } + case 2: + return "\033[0m --Coords: {"+this.x+";"+this.y+";"+this.z+"} \t|"; + case 3: + return "\033[0m --Cap: "+this.cap+"\t\t\t|"; + case 4: + if(this.isDead){ + return "\033[4;37;41m ATTENTION: avion hors ligne\t|\033[0m"; + }else if(this.speed<50){ + return "\033[5;37;41m --Speed: "+this.speed+"\t\t\t|\033[0m"; + }else{ + return "\033[0m --Speed: "+this.speed+"\t\t\t|"; + } + default: + return ""; + } + } + + public byte[] toBytes(){ + ByteBuffer buf = ByteBuffer.allocate(26); + buf.put(this.code.getBytes()); + //EOL char + buf.put((byte)0); + buf.putInt(this.x); + buf.putInt(this.y); + buf.putInt(this.z); + buf.putInt(this.cap); + buf.putInt(this.speed); + + return buf.array(); + } + +} diff --git a/command-terminal/src/ControlTerminal/PlaneContainer.java b/command-terminal/src/ControlTerminal/PlaneContainer.java new file mode 100644 index 0000000..fdbb4b4 --- /dev/null +++ b/command-terminal/src/ControlTerminal/PlaneContainer.java @@ -0,0 +1,91 @@ +package ControlTerminal; + +import java.net.DatagramPacket; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.HashMap; + +import DatagramSocket.AsynchronousDatagramSocket; + +public class PlaneContainer { + + private HashMap map; + private AsynchronousDatagramSocket socket; + private Printer printer; + + public PlaneContainer(){ + this.map = new HashMap(); + } + + public void bindSocket(AsynchronousDatagramSocket s){ + this.socket = s; + } + + public void bindPrinter(Printer p){ + this.printer = p; + } + + public void notifyReceive() throws InvalidFlagException{ + DatagramPacket packet = this.socket.synchronousReceive(); + + ByteBuffer buf = ByteBuffer.wrap(packet.getData()); + + byte flag; + byte nbrPlane; + ArrayList codes; + + flag = buf.get(); + nbrPlane = buf.get(); + + codes = new ArrayList(nbrPlane); + + //System.out.println("Processing "+nbrPlane+" planes"); + + if(flag == 0){ + //this is a ping response + return; + }else if((flag&(byte)0x01) != 1){ + throw new InvalidFlagException("Flag is not a feedback flag :"+flag); + }else{ + String code; + byte rawCode[] = new byte[5]; + Plane plane; + for(int i = 0;i getMap(){ + return this.map; + } +} diff --git a/command-terminal/src/ControlTerminal/Printer.java b/command-terminal/src/ControlTerminal/Printer.java new file mode 100644 index 0000000..8cb0c22 --- /dev/null +++ b/command-terminal/src/ControlTerminal/Printer.java @@ -0,0 +1,54 @@ +package ControlTerminal; + +import java.util.HashMap; + +public class Printer { + + private PlaneContainer container; + + public Printer(){ + + } + + public void bindContainer(PlaneContainer c){ + this.container = c; + } + + + public void notifyReceive(){ + System.out.println("\033[2J \033[H"); + HashMap map = this.container.getMap(); + int i = 0; + + String lines[] = new String[5]; + for(int k = 0;k<5;k++){ + lines[k] = ""; + } + + if(map.keySet().size() == 0){ + System.out.println("\033[37;43m No plane connected \033[0m"); + }else{ + for(String code : map.keySet()){ + if(i <= 1){ + for(int k = 0;k<5;k++){ + lines[k] += map.get(code).getLine(k); + } + i++; + }else{ + for(int k = 0;k<5;k++){ + System.out.println(lines[k]); + lines[k] = ""; + } + for(int k = 0;k<5;k++){ + lines[k] += map.get(code).getLine(k); + } + i=1; + } + } + for(int k = 0;k<5;k++){ + System.out.println(lines[k]); + } + } + System.out.println("Please enter your command (ENTER to update data, u to update a plane)"); + } +} diff --git a/command-terminal/src/DatagramSocket/AsynchronousDatagramSocket.java b/command-terminal/src/DatagramSocket/AsynchronousDatagramSocket.java new file mode 100644 index 0000000..3ab59d6 --- /dev/null +++ b/command-terminal/src/DatagramSocket/AsynchronousDatagramSocket.java @@ -0,0 +1,89 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + +package DatagramSocket; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.SocketException; +import java.util.logging.Level; +import java.util.logging.Logger; + +import ControlTerminal.InvalidFlagException; +import ControlTerminal.PlaneContainer; + +/** + * + * @author lmascaro + */ +public class AsynchronousDatagramSocket implements Runnable, AutoCloseable{ + + public final static int MAX_MESSAGE_SIZE = 300; + + private SynchronizedBuffer buf; + private DatagramSocket socket; + private PlaneContainer container; + + public AsynchronousDatagramSocket() throws SocketException{ + this.buf = new SynchronizedBuffer<>(); + this.socket = new DatagramSocket(); + new Thread(this).start(); + } + + public AsynchronousDatagramSocket(int port) throws SocketException{ + this.buf = new SynchronizedBuffer<>(); + this.socket = new DatagramSocket(port); + new Thread(this).start(); + } + + public void bindContainer(PlaneContainer c){ + this.container = c; + } + + public void send(DatagramPacket dp) throws IOException{ + this.socket.send(dp); + } + + public boolean asynchronousReceive(DatagramPacket dp){ + if(this.buf.available() == 0){ + return false; + }else{ + dp = this.buf.removeElement(false); + return true; + } + } + + public DatagramPacket synchronousReceive(){ + return this.buf.removeElement(true); + } + + public boolean available(){ + return this.buf.available()>0; + } + + @Override + public void close(){ + this.socket.close(); + } + + @Override + public void run() { + DatagramPacket packet; + while(true){ + packet = new DatagramPacket(new byte[MAX_MESSAGE_SIZE],MAX_MESSAGE_SIZE); + try { + this.socket.receive(packet); + this.buf.addElement(packet); + this.container.notifyReceive(); + } catch (IOException ex) { + Logger.getLogger(AsynchronousDatagramSocket.class.getName()).log(Level.SEVERE, null, ex); + } catch (InvalidFlagException e) { + System.out.println("\033[01;31m Unexpected flag received \033[0m"); + } + } + } +} diff --git a/command-terminal/src/DatagramSocket/SynchronizedBuffer.java b/command-terminal/src/DatagramSocket/SynchronizedBuffer.java new file mode 100644 index 0000000..2f28f9c --- /dev/null +++ b/command-terminal/src/DatagramSocket/SynchronizedBuffer.java @@ -0,0 +1,46 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + +package DatagramSocket; + +import java.util.LinkedList; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author lmascaro + */ +public class SynchronizedBuffer{ + + private LinkedList elements = new LinkedList(); + + public synchronized T removeElement(boolean sync){ + if(!sync && this.elements.isEmpty()){ + return null; + } + + while(this.elements.isEmpty()){ + try { + this.wait(); + } catch (InterruptedException ex) { + Logger.getLogger(SynchronizedBuffer.class.getName()).log(Level.SEVERE, null, ex); + } + } + + return this.elements.removeFirst(); + } + + public synchronized void addElement(T elem){ + this.elements.add(elem); + this.notifyAll(); + } + + public synchronized int available(){ + return this.elements.size(); + } + +}