All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.sdnwiselab.sdnwise.node.Node Maven / Gradle / Ivy

/*
 * Copyright (C) 2015 SDN-WISE
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package com.github.sdnwiselab.sdnwise.node;

import com.github.sdnwiselab.sdnwise.flowtable.FlowTableAction;
import static com.github.sdnwiselab.sdnwise.flowtable.FlowTableAction.SDN_WISE_AGGREGATE;
import static com.github.sdnwiselab.sdnwise.flowtable.FlowTableAction.SDN_WISE_DROP;
import static com.github.sdnwiselab.sdnwise.flowtable.FlowTableAction.SDN_WISE_FORWARD_BROADCAST;
import static com.github.sdnwiselab.sdnwise.flowtable.FlowTableAction.SDN_WISE_FORWARD_UNICAST;
import static com.github.sdnwiselab.sdnwise.flowtable.FlowTableAction.SDN_WISE_FORWARD_UP;
import static com.github.sdnwiselab.sdnwise.flowtable.FlowTableAction.SDN_WISE_MODIFY;
import com.github.sdnwiselab.sdnwise.flowtable.FlowTableEntry;
import static com.github.sdnwiselab.sdnwise.flowtable.FlowTableEntry.SDN_WISE_WINDOWS_MAX;
import com.github.sdnwiselab.sdnwise.flowtable.FlowTableStats;
import com.github.sdnwiselab.sdnwise.flowtable.FlowTableWindow;
import static com.github.sdnwiselab.sdnwise.flowtable.FlowTableWindow.SDN_WISE_BIGGER;
import static com.github.sdnwiselab.sdnwise.flowtable.FlowTableWindow.SDN_WISE_EQUAL;
import static com.github.sdnwiselab.sdnwise.flowtable.FlowTableWindow.SDN_WISE_EQUAL_OR_BIGGER;
import static com.github.sdnwiselab.sdnwise.flowtable.FlowTableWindow.SDN_WISE_EQUAL_OR_LESS;
import static com.github.sdnwiselab.sdnwise.flowtable.FlowTableWindow.SDN_WISE_LESS;
import static com.github.sdnwiselab.sdnwise.flowtable.FlowTableWindow.SDN_WISE_NOT_EQUAL;
import static com.github.sdnwiselab.sdnwise.flowtable.FlowTableWindow.SDN_WISE_PACKET;
import static com.github.sdnwiselab.sdnwise.flowtable.FlowTableWindow.SDN_WISE_SIZE_0;
import static com.github.sdnwiselab.sdnwise.flowtable.FlowTableWindow.SDN_WISE_SIZE_1;
import static com.github.sdnwiselab.sdnwise.flowtable.FlowTableWindow.SDN_WISE_SIZE_2;
import com.github.sdnwiselab.sdnwise.function.FunctionInterface;
import static com.github.sdnwiselab.sdnwise.node.Constants.SDN_WISE_ACCEPTED_ID_MAX;
import static com.github.sdnwiselab.sdnwise.node.Constants.SDN_WISE_BEACON_HDR_LEN;
import static com.github.sdnwiselab.sdnwise.node.Constants.SDN_WISE_DFLT_CNT_BEACON_MAX;
import static com.github.sdnwiselab.sdnwise.node.Constants.SDN_WISE_DFLT_CNT_REPORT_MAX;
import static com.github.sdnwiselab.sdnwise.node.Constants.SDN_WISE_DFLT_CNT_UPDTABLE_MAX;
import static com.github.sdnwiselab.sdnwise.node.Constants.SDN_WISE_DFLT_HDR_LEN;
import static com.github.sdnwiselab.sdnwise.node.Constants.SDN_WISE_DFLT_RSSI_MIN;
import static com.github.sdnwiselab.sdnwise.node.Constants.SDN_WISE_MAC_SEND_BROADCAST;
import static com.github.sdnwiselab.sdnwise.node.Constants.SDN_WISE_MAC_SEND_UNICAST;
import static com.github.sdnwiselab.sdnwise.node.Constants.SDN_WISE_NEIGHBORS_MAX;
import static com.github.sdnwiselab.sdnwise.node.Constants.SDN_WISE_OPEN_PATH_HDR_LEN;
import static com.github.sdnwiselab.sdnwise.node.Constants.SDN_WISE_REPORT_HDR_LEN;
import static com.github.sdnwiselab.sdnwise.node.Constants.SDN_WISE_RESPONSE_HDR_LEN;
import static com.github.sdnwiselab.sdnwise.node.Constants.SDN_WISE_RLS_MAX;
import static com.github.sdnwiselab.sdnwise.flowtable.FlowTableEntry.SDN_WISE_RULE_COPY_LEN;
import static com.github.sdnwiselab.sdnwise.node.Constants.SDN_WISE_RL_TTL_DECR;
import com.github.sdnwiselab.sdnwise.packet.NetworkPacket;
import static com.github.sdnwiselab.sdnwise.packet.NetworkPacket.SDN_WISE_BATT;
import static com.github.sdnwiselab.sdnwise.packet.NetworkPacket.SDN_WISE_BEACON;
import static com.github.sdnwiselab.sdnwise.packet.NetworkPacket.SDN_WISE_CONFIG;
import static com.github.sdnwiselab.sdnwise.packet.NetworkPacket.SDN_WISE_DATA;
import static com.github.sdnwiselab.sdnwise.packet.NetworkPacket.SDN_WISE_DFLT_TTL_MAX;
import static com.github.sdnwiselab.sdnwise.packet.NetworkPacket.SDN_WISE_DIST;
import static com.github.sdnwiselab.sdnwise.packet.NetworkPacket.SDN_WISE_DST_H;
import static com.github.sdnwiselab.sdnwise.packet.NetworkPacket.SDN_WISE_DST_L;
import static com.github.sdnwiselab.sdnwise.packet.NetworkPacket.SDN_WISE_LEN;
import static com.github.sdnwiselab.sdnwise.packet.NetworkPacket.SDN_WISE_NEIGH;
import static com.github.sdnwiselab.sdnwise.packet.NetworkPacket.SDN_WISE_NET_ID;
import static com.github.sdnwiselab.sdnwise.packet.NetworkPacket.SDN_WISE_NXHOP_H;
import static com.github.sdnwiselab.sdnwise.packet.NetworkPacket.SDN_WISE_NXHOP_L;
import static com.github.sdnwiselab.sdnwise.packet.NetworkPacket.SDN_WISE_OPEN_PATH;
import static com.github.sdnwiselab.sdnwise.packet.NetworkPacket.SDN_WISE_REPORT;
import static com.github.sdnwiselab.sdnwise.packet.NetworkPacket.SDN_WISE_RESPONSE;
import static com.github.sdnwiselab.sdnwise.packet.NetworkPacket.SDN_WISE_SRC_H;
import static com.github.sdnwiselab.sdnwise.packet.NetworkPacket.SDN_WISE_SRC_L;
import static com.github.sdnwiselab.sdnwise.packet.NetworkPacket.SDN_WISE_TTL;
import static com.github.sdnwiselab.sdnwise.packet.NetworkPacket.SDN_WISE_TYPE;
import com.github.sdnwiselab.sdnwise.util.Neighbor;
import com.github.sdnwiselab.sdnwise.util.NodeAddress;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PublicKey;
import java.security.Security;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;

/**
 *
 * @author Sebastiano Milardo
 */
public abstract class Node implements Runnable {
    private static final String digits = "0123456789abcdef";

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        Thread th;
        
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        if (Security.getProvider("BC") == null) {
            System.out.println("Provider(\"BC\") not installed");
        } else {
            System.out.println("Provider(\"BC\") installed");
        }      
        
        if (args.length == 7) {
            if (args[0].equals("SINK")) {
                th = new Thread(new SinkNode(
                        // its own id
                        (byte) Integer.parseInt(args[1]),
                        // its own address
                        new NodeAddress(args[2]),
                        // listener port
                        Integer.parseInt(args[3]),
                        // controller address
                        args[4],
                        // controller port
                        Integer.parseInt(args[5]),
                        // neigh file
                        args[6], 
                        // security
                        false)
                );
                th.start();
            }
        } else if (args.length == 5) {
            if (args[0].equals("NODE")) {
                th = new Thread(new SensorNode(
                        // its own id
                        (byte) Integer.parseInt(args[1]),
                        // its own address
                        new NodeAddress(args[2]),
                        // listener port
                        Integer.parseInt(args[3]),
                        // neigh file
                        args[4], false)
                );
                th.start();
            }
        }
    }

    /**
     * Return length many bytes of the passed in byte array as a hex string.
     *
     * @param data the bytes to be converted.
     * @param length the number of bytes in the data block to be converted.
     * @return a hex representation of length bytes of data.
     */
    public static String toHex(byte[] data, int length) {
        StringBuffer buf = new StringBuffer();
        
        for (int i = 0; i != length; i++) {
            int v = data[i] & 0xff;
            
            buf.append(digits.charAt(v >> 4));
            buf.append(digits.charAt(v & 0xf));
        }
        
        return buf.toString();
    }

    /**
     * Return the passed in byte array as a hex string.
     *
     * @param data the bytes to be converted.
     * @return a hex representation of data.
     */
    public static String toHex(byte[] data) {
        return toHex(data, data.length);
    }

    int port;
    DatagramSocket socket;

    final ArrayBlockingQueue messageQueue;
    HashMap neighbourList;
    String configNeighbourFilePath;

    private int num_hop_vs_sink;
    private int rssi_vs_sink;

    Battery battery;

    int semaphore,
            flow_table_free_pos,
            accepted_id_free_pos,
            neighbors_number;

    private final byte[] buf;

    ArrayList neighborTable;
    ArrayList flowTable;
    ArrayList acceptedId;
    int[] statusRegister;
    HashMap adcRegister;

    HashMap> functionBuffer = new HashMap<>();
    HashMap functions = new HashMap<>();

    NodeAddress addr;
    int net_id;
    int cnt_beacon_max;
    int cnt_report_max;
    int cnt_updtable_max;
    int cnt_sleep_max;
    int ttl_max;
    int rssi_min;

    boolean isSecure = false;
    Cipher cipher;
    KeyPair pair;
    Key pubKey, privKey;
    PublicKey sinkPubKey;

    public Node(NodeAddress addr, byte net_id, int port, String configNeighbourFilePath, boolean isSecure) {
        buf = new byte[1024];
        
        statusRegister = new int[1024];
        neighborTable = new ArrayList<>(SDN_WISE_NEIGHBORS_MAX);
        acceptedId = new ArrayList<>(SDN_WISE_ACCEPTED_ID_MAX);
        flowTable = new ArrayList<>(SDN_WISE_RLS_MAX);

        messageQueue = new ArrayBlockingQueue<>(1024);
        this.addr = addr;
        this.net_id = net_id;
        this.configNeighbourFilePath = configNeighbourFilePath;

        neighbourList = new HashMap<>();

        this.port = port;

        this.isSecure = isSecure;
        setup();
    }

    public void setNum_hop_vs_sink(int num_hop_vs_sink) {
        this.num_hop_vs_sink = num_hop_vs_sink;
    }

    public void setRssi_vs_sink(int rssi_vs_sink) {
        this.rssi_vs_sink = rssi_vs_sink;
    }

    public void setSemaphore(int semaforo) {
        this.semaphore = semaforo;
    }

    public int getNum_hop_vs_sink() {
        return num_hop_vs_sink;
    }

    public int getRssi_vs_sink() {
        return rssi_vs_sink;
    }

    public int getSemaphore() {
        return semaphore;
    }

    private void setup() {
        initSdnWise();
        initFlowTable();
        initNeighborTable();
        initAcceptedId();
        //boolean
        if (isSecure == true) {
            setupSecurity();
        }
    }

    public abstract void setupSecurity();

    // questi due metodi sono inglobati nel tx e rx Beacon
    public int[] sendPublicKey(int[] packet) {
        int[] newPacket = new int[packet.length + sinkPubKey.getEncoded().length];
        System.arraycopy(packet, 0, newPacket, 0, packet.length);
        arraycopy(sinkPubKey.getEncoded(), 0, newPacket, packet.length, sinkPubKey.getEncoded().length);
        newPacket[SDN_WISE_LEN] = newPacket.length;
        return newPacket;
    }
    public void receivePublicKey(int[] allPacket, int keyLen) {
        
        byte[] sinkPubKeyArray = new byte[keyLen]; // lo sappiamo quanto di e'
        
        arraycopy(allPacket, allPacket.length - sinkPubKeyArray.length,
                sinkPubKeyArray, 0, sinkPubKeyArray.length);
        
        try {
            sinkPubKey = KeyFactory.getInstance("RSA").
                    generatePublic(new X509EncodedKeySpec(sinkPubKeyArray));
        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(Node.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvalidKeySpecException ex) {
            Logger.getLogger(Node.class.getName()).log(Level.SEVERE, null, ex);
        }
        
    }

    //
    public int[] sendSignedMessage(int[] packet) {
        if (packet.length > SDN_WISE_DFLT_HDR_LEN) {
            byte[] plainPacket = new byte[packet.length - SDN_WISE_DFLT_HDR_LEN];

            try {
                arraycopy(packet, SDN_WISE_DFLT_HDR_LEN,
                        plainPacket, 0, packet.length - SDN_WISE_DFLT_HDR_LEN);

                MessageDigest messageHash = MessageDigest.getInstance("SHA1", "BC");
                byte[] messageHashed = messageHash.digest(plainPacket);
                System.out.println("plainMessage: " + Arrays.toString(plainPacket));
                System.out.println("plainMessageString: " + toHex(plainPacket));
                System.out.println("messageHashed : " + Arrays.toString(messageHashed));
                System.out.println("messageHashedString : " + toHex(messageHashed));
                System.out.println("messageHashed Length: " + messageHashed.length);
                System.out.println("messageHashedString Length: " + (toHex(messageHashed)).length());

                cipher.init(Cipher.ENCRYPT_MODE, privKey);// ,random
                byte[] encryptedPart = cipher.doFinal(messageHashed);
                System.out.println("cipher: " + toHex(encryptedPart));
                System.out.println("cipher lenght: " + toHex(encryptedPart).length());
                System.out.println("cipher[] : " + Arrays.toString(encryptedPart));
                System.out.println("cipher[] lenght: " + encryptedPart.length);
                System.out.println("Encrypted Hashed Message Sent!");

                int[] newPacket = new int[packet.length + encryptedPart.length];
                System.arraycopy(packet, 0, newPacket, 0, packet.length);
                arraycopy(encryptedPart, 0, newPacket, packet.length, encryptedPart.length);

                return newPacket;
            } catch (NoSuchAlgorithmException |
                    NoSuchProviderException |
                    InvalidKeyException |
                    IllegalBlockSizeException |
                    BadPaddingException ex) {
                Logger.getLogger(Node.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return packet;
    }
    public int[] receiveSignedMessage(int[] allPacket) {
        byte[] encryptedPart = new byte[22];
        byte[] plainPart = new byte[allPacket.length - encryptedPart.length - SDN_WISE_DFLT_HDR_LEN];

        arraycopy(allPacket, SDN_WISE_DFLT_HDR_LEN, plainPart, 0, plainPart.length);
        arraycopy(allPacket, allPacket.length - encryptedPart.length,
                encryptedPart, 0, encryptedPart.length);

        try {
            // decryption step
            //Cipher cipher = Cipher.getInstance("RSA/None/NoPadding", "BC");
            cipher.init(Cipher.DECRYPT_MODE, sinkPubKey);
            byte[] hashedPart = cipher.doFinal(encryptedPart);

            MessageDigest hashedPlainPart = MessageDigest.getInstance("SHA1", "BC");
            byte[] hastToVerify = hashedPlainPart.digest(plainPart);

            //verifica autenticita' messaggio
            if (Arrays.equals(hashedPart, hastToVerify)) {
                System.out.println("Signature Verification Correct");
                return allPacket;
            } else {
                System.out.println("Signature Verification Failed");
                return null;
            }
            
        } catch (InvalidKeyException |
                IllegalBlockSizeException |
                BadPaddingException |
                NoSuchAlgorithmException | 
                NoSuchProviderException ex) {
            Logger.getLogger(Node.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    public void initSdnWise() {
        cnt_beacon_max = SDN_WISE_DFLT_CNT_BEACON_MAX;
        cnt_report_max = SDN_WISE_DFLT_CNT_REPORT_MAX;
        cnt_updtable_max = SDN_WISE_DFLT_CNT_UPDTABLE_MAX;
        rssi_min = SDN_WISE_DFLT_RSSI_MIN;
        ttl_max = SDN_WISE_DFLT_TTL_MAX;

        battery = new Battery();
        flow_table_free_pos = 1;
        accepted_id_free_pos = 0;
        
        InputStream is = this.getClass().getResourceAsStream("/"+configNeighbourFilePath);
        
        try (BufferedReader br = new BufferedReader(new InputStreamReader(is,"UTF-8"))) {
            String line;
            while ((line = br.readLine()) != null) {
                String[] tmp = line.split(",");
                if (tmp.length == 4) {
                    neighbourList.put(new NodeAddress(tmp[0]), new FakeInfo(
                            new InetSocketAddress(tmp[1],
                                    Integer.parseInt(tmp[2])),
                            Integer.parseInt(tmp[3]))
                    );
                }
            }
        } catch (Exception ex) {
            Logger.getLogger(SinkNode.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void initFlowTable() {
        for (int i = 0; i < SDN_WISE_RLS_MAX; i++) {
            flowTable.add(i, new FlowTableEntry());
        }

        int i, k;

        flowTable.get(0).getWindow()[0]
                .setOperator(SDN_WISE_EQUAL)
                .setSize(SDN_WISE_SIZE_2)
                .setLocation(SDN_WISE_PACKET)
                .setPos(SDN_WISE_DST_H)
                .setValueHigh(0)
                .setValueLow(0);

        flowTable.get(0).getWindow()[1]
                .setOperator(SDN_WISE_NOT_EQUAL)
                .setSize(SDN_WISE_SIZE_1)
                .setLocation(SDN_WISE_PACKET)
                .setPos(SDN_WISE_TYPE)
                .setValueHigh(0)
                .setValueLow(0);

        for (k = 2; k < SDN_WISE_WINDOWS_MAX; k++) {
            flowTable.get(0).getWindow()[k] = new FlowTableWindow();
        }

        flowTable.get(0).getAction()
                .setType(SDN_WISE_FORWARD_UNICAST)
                .setLocation(SDN_WISE_PACKET)
                .setPos(SDN_WISE_NXHOP_H)
                .setValueHigh(0)
                .setValueLow(0);

        flowTable.get(0).setStats(new FlowTableStats());

        for (i = 1; i < SDN_WISE_RLS_MAX; i++) {
            initRule(flowTable.get(i));
        }
    }

    public void initNeighborTable() {
        int i;
        for (i = 0; i < SDN_WISE_NEIGHBORS_MAX; i++) {
            neighborTable.add(i, new Neighbor());
        }
        neighbors_number = 0;
    }

    public void initAcceptedId() {
        int i;
        for (i = 0; i < SDN_WISE_ACCEPTED_ID_MAX; i++) {
            acceptedId.add(i, new NodeAddress(65535));
        }
    }

    public void initRule(FlowTableEntry rule) {
        int i;
        for (i = 0; i < SDN_WISE_WINDOWS_MAX; i++) {
            rule.getWindow()[i] = new FlowTableWindow();
        }
        rule.setAction(new FlowTableAction());
        rule.setStats(new FlowTableStats());
    }

    public int chooseNeighbor(int action_value_2_byte) {
        int i;
        for (i = 0; i < SDN_WISE_NEIGHBORS_MAX; i++) {
            if (action_value_2_byte == neighborTable.get(i).getAddr().getLow()) {
                return (neighborTable.get(i).getAddr().getHigh());
            }
        }
        return 254;
    }

    public void resetSemaphore() {
    }

    @Override
    public void run() {
        try {
            DatagramPacket packet = new DatagramPacket(buf, buf.length);
            socket = new DatagramSocket(port);
            new Timer().schedule(new Task(), 1000, 1000);
            new Thread(new PacketManager()).start();
            
            while (true) {
                socket.receive(packet);
                int[] tmp = new int[packet.getData()[0]];

                for (int i = 0; i < packet.getLength(); i++) {
                    tmp[i] = packet.getData()[i] & 0xFF;
                }

                messageQueue.put(tmp);
            }

        } catch (IOException | InterruptedException ex) {
            Logger.getLogger(Node.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    void txBEACON() {
        int[] packet = new int[SDN_WISE_BEACON_HDR_LEN];
        packet[SDN_WISE_LEN] = SDN_WISE_BEACON_HDR_LEN;
        packet[SDN_WISE_NET_ID] = net_id;
        packet[SDN_WISE_SRC_H] = addr.getHigh();
        packet[SDN_WISE_SRC_L] = addr.getLow();

        packet[SDN_WISE_DST_H] = 255; // Broadcast
        packet[SDN_WISE_DST_L] = 255;
        packet[SDN_WISE_TYPE] = SDN_WISE_BEACON;
        packet[SDN_WISE_TTL] = ttl_max;
        packet[SDN_WISE_DIST] = num_hop_vs_sink;
        packet[SDN_WISE_BATT] = battery.getBatteryPercent();
        if (num_hop_vs_sink == 0) {
            packet[SDN_WISE_NXHOP_H] = addr.getHigh();
            packet[SDN_WISE_NXHOP_L] = addr.getLow();
        } else {
            packet[SDN_WISE_NXHOP_H] = flowTable.get(0).getWindow()[0].getValueHigh();
            packet[SDN_WISE_NXHOP_L] = flowTable.get(0).getWindow()[0].getValueLow();
        }

        if (this.isSecure) {
            packet = sendPublicKey(packet);
        }    
        radioTX(packet, SDN_WISE_MAC_SEND_BROADCAST);
    }

    void txREPORT() {
        int i = 0;

        int[] packet = new int[16 + SDN_WISE_NEIGHBORS_MAX * 3];
        packet[SDN_WISE_NET_ID] = net_id;
        packet[SDN_WISE_SRC_H] = addr.getHigh();
        packet[SDN_WISE_SRC_L] = addr.getLow();
        packet[SDN_WISE_DST_H] = flowTable.get(0).getWindow()[0].getValueHigh(); // indirizzo del sink
        packet[SDN_WISE_DST_L] = flowTable.get(0).getWindow()[0].getValueLow();;
        packet[SDN_WISE_TYPE] = SDN_WISE_REPORT;
        packet[SDN_WISE_TTL] = ttl_max;
        packet[SDN_WISE_NXHOP_H] = flowTable.get(0).getAction().getValueHigh();
        // Nel seguito si farà uso dell'accesso diretto a qst
        packet[SDN_WISE_NXHOP_L] = flowTable.get(0).getAction().getValueLow();
        //  ints perchè la regola 0 è sempre diretta verso il sink
        packet[SDN_WISE_DIST] = num_hop_vs_sink;
        packet[SDN_WISE_BATT] = battery.getBatteryPercent();
        packet[SDN_WISE_NEIGH] = neighbors_number; //numero di vicini
        packet[SDN_WISE_LEN] = ((neighbors_number * 3) + SDN_WISE_REPORT_HDR_LEN);

        for (int j = 0; j < packet[SDN_WISE_NEIGH]; j++) {
            //Vicino i
            packet[SDN_WISE_REPORT_HDR_LEN + i] = neighborTable.get(j)
                    .getAddr().getHigh();
            i++;
            packet[SDN_WISE_REPORT_HDR_LEN + i] = neighborTable.get(j)
                    .getAddr().getLow();
            i++;
            //RSSI vs Vicino
            packet[SDN_WISE_REPORT_HDR_LEN + i] = neighborTable.get(j)
                    .getRssi();
            i++;
        }
        initNeighborTable();
        controllerTX(Arrays.copyOf(packet, packet[SDN_WISE_LEN]));
    }

    void updateTable() {
        for (int i = 0; i < SDN_WISE_RLS_MAX; i++) {
            int ttl = flowTable.get(i).getStats().getTtl();
            if (ttl >= SDN_WISE_RL_TTL_DECR) {
                flowTable.get(i).getStats().setTtl((ttl - SDN_WISE_RL_TTL_DECR));
            } else {
                initRule(flowTable.get(i));
                if (i == 0) {
                    resetSemaphore();
                }
            }
        }
    }

    void rxDATA(int[] packet) {
        if (isAcceptedIdPacket(packet)) {
            SDN_WISE_Callback(packet);
        } else if (isAcceptedIdAddress(
                packet[SDN_WISE_NXHOP_H],
                packet[SDN_WISE_NXHOP_L])) {
            runFlowMatch(packet);
        }
    }

    void rxBEACON(int[] packet, int rssi) {
        int index = getNeighborIndex(new NodeAddress(packet[SDN_WISE_SRC_H],
                packet[SDN_WISE_SRC_L]));

        if (index != (SDN_WISE_NEIGHBORS_MAX + 1)) {
            if (index != -1) {
                neighborTable.get(index).setRssi(rssi);
                neighborTable.get(index).setBatt(packet[SDN_WISE_BATT]);
            } else {
                neighborTable.get(neighbors_number).setAddr(
                        new NodeAddress(packet[SDN_WISE_SRC_H],
                                packet[SDN_WISE_SRC_L]));

                neighborTable.get(neighbors_number).setRssi(rssi);
                neighborTable.get(neighbors_number).setBatt(packet[SDN_WISE_BATT]);
                neighbors_number++;
            }
        }
    }

    abstract void rxREPORT(int[] packet);

    void rxRESPONSE(int[] packet) {
        if (isAcceptedIdPacket(packet)) {
            // Si memorizza la regola nella tabella
            // Vedo se esiste una regola uguale

            // Vedo quante regole ci sono nel pacchetto
            int nRules = (packet[SDN_WISE_LEN] - SDN_WISE_RESPONSE_HDR_LEN) / SDN_WISE_RULE_COPY_LEN;

            if ((nRules * SDN_WISE_RULE_COPY_LEN) + SDN_WISE_RESPONSE_HDR_LEN == packet[SDN_WISE_LEN]) {
                for (int i = 0; i < nRules; i++) {
                    FlowTableEntry rule = new FlowTableEntry();
                    int j;
                    int packet_index = SDN_WISE_RESPONSE_HDR_LEN;

                    for (j = 0; j < SDN_WISE_WINDOWS_MAX; j++) {
                        rule.getWindow()[j].setOp(packet[packet_index]);
                        packet_index++;
                        rule.getWindow()[j].setPos(packet[packet_index]);
                        packet_index++;
                        rule.getWindow()[j].setValueHigh(packet[packet_index]);
                        packet_index++;
                        rule.getWindow()[j].setValueLow(packet[packet_index]);
                        packet_index++;
                    }

                    rule.getAction().setAct(packet[packet_index]);
                    packet_index++;
                    rule.getAction().setPos(packet[packet_index]);
                    packet_index++;
                    rule.getAction().setValueHigh(packet[packet_index]);
                    packet_index++;
                    rule.getAction().setValueLow(packet[packet_index]);
                    packet_index++;

                    rule.setStats(new FlowTableStats());

                    insertRule(rule, searchRule(rule));
                }
            }
        } else {
            runFlowMatch(packet);
        }
    }

    void rxOPEN_PATH(int[] packet) {
        if (isAcceptedIdPacket(packet)) {
            int i;

            i = SDN_WISE_OPEN_PATH_HDR_LEN;

            NodeAddress last_path_addr
                    = new NodeAddress(packet[packet[SDN_WISE_LEN] - 2],
                            packet[packet[SDN_WISE_LEN] - 1]);

            NodeAddress first_path_addr
                    = new NodeAddress(packet[SDN_WISE_OPEN_PATH_HDR_LEN],
                            packet[SDN_WISE_OPEN_PATH_HDR_LEN + 1]);

            // mi cerco
            while (i < packet[SDN_WISE_LEN]) {
                // mi trovo
                if (isAcceptedIdAddress(packet[i], packet[i + 1])) {

                    NodeAddress actual_address
                            = new NodeAddress(packet[i], packet[i + 1]);

                    // se non sono il primo
                    if (!actual_address.equals(first_path_addr)) {
                        FlowTableEntry rule = new FlowTableEntry();
                        initRule(rule);

                        //regola per forwardare indietro
                        rule.getWindow()[0]
                                .setOperator(SDN_WISE_EQUAL)
                                .setSize(SDN_WISE_SIZE_2)
                                .setLocation(SDN_WISE_PACKET);

                        rule.getWindow()[0].setPos(SDN_WISE_DST_H);
                        rule.getWindow()[0].setValueHigh(first_path_addr.getHigh());
                        rule.getWindow()[0].setValueLow(first_path_addr.getLow());

                        rule.getAction()
                                .setType(SDN_WISE_FORWARD_UNICAST)
                                .setLocation(SDN_WISE_PACKET);

                        rule.getAction().setPos(SDN_WISE_NXHOP_H);
                        rule.getAction().setValueHigh(packet[i - 2]);
                        rule.getAction().setValueLow(packet[i - 1]);
                        //e la imparo
                        int p = searchRule(rule);
                        insertRule(rule, p);
                    }

                    if (!actual_address.equals(last_path_addr)) {
                        FlowTableEntry rule = new FlowTableEntry();
                        initRule(rule);

                        //regola per forwardare avanti
                        rule.getWindow()[0]
                                .setOperator(SDN_WISE_EQUAL)
                                .setSize(SDN_WISE_SIZE_2)
                                .setLocation(SDN_WISE_PACKET);

                        rule.getWindow()[0].setPos(SDN_WISE_DST_H);

                        rule.getWindow()[0].setValueHigh(last_path_addr.getHigh());

                        rule.getWindow()[0].setValueLow(last_path_addr.getLow());

                        rule.getAction()
                                .setType(SDN_WISE_FORWARD_UNICAST)
                                .setLocation(SDN_WISE_PACKET);
                        rule.getAction().setPos(SDN_WISE_NXHOP_H);
                        rule.getAction().setValueHigh(packet[i + 2]);
                        rule.getAction().setValueLow(packet[i + 3]);
                        //e la imparo
                        int p = searchRule(rule);
                        insertRule(rule, p);

                        //cambio next hop e dest del pacchetto
                        packet[SDN_WISE_DST_H] = packet[i + 2];
                        packet[SDN_WISE_DST_L] = packet[i + 3];
                        packet[SDN_WISE_NXHOP_H] = packet[i + 2];
                        packet[SDN_WISE_NXHOP_L] = packet[i + 3];
                        // e forwardo
                        radioTX(packet, SDN_WISE_MAC_SEND_UNICAST);
                        break;
                    }
                }
                i += 2;
            }
        } else {
            runFlowMatch(packet);
        }
    }

    void runFlowMatch(int[] packet) {
        int j, i, found = 0;
        for (j = 0; j < SDN_WISE_RLS_MAX; j++) {

            i = getActualFlowIndex(j);

            if (matchRule(flowTable.get(i), packet) == 1) {
                found = 1;
                runAction(flowTable.get(i).getAction(), packet);
                flowTable.get(i).getStats().setCounter(flowTable.get(i).getStats().getCounter() + 1);
                if (!(flowTable.get(i).getAction().getMultimatch())) {
                    break;
                }
            }
        }
        if (found == 0) { //!found
            // It's necessary to send a rule/request if we have done the lookup
            // I must modify the source address with myself,
            packet[SDN_WISE_SRC_H] = addr.getHigh();
            packet[SDN_WISE_SRC_L] = addr.getLow();
            // il nuovo tipo è impostato a: il tipo originale + 128
            packet[SDN_WISE_TYPE] += 128;
            packet[SDN_WISE_TTL] = ttl_max;
            // The next hop at the moment will be the best hop to reach the sink
            // So, in this case forward the packet
            packet[SDN_WISE_NXHOP_H] = flowTable.get(0).getAction().getValueHigh();
            packet[SDN_WISE_NXHOP_L] = flowTable.get(0).getAction().getValueLow();
            // Send Rule/Request packet

            controllerTX(packet);
        }
    }

    abstract void rxCONFIG(int[] packet);

    void insertRule(FlowTableEntry rule, int pos) {
        if (pos >= SDN_WISE_RLS_MAX) {
            pos = flow_table_free_pos; // TODO controllare
            flow_table_free_pos++;
            if (flow_table_free_pos >= SDN_WISE_RLS_MAX) {
                flow_table_free_pos = 1;
            }
        }
        flowTable.set(pos, rule);
    }

    // Verifica che una condizione di una finestra di una regola è soddisfatta
    int matchWindow(FlowTableWindow window, int[] packet) {

        int size = window.getSize();
        int operatore = window.getOperator();
        int matchMemory = window.getLocation();
        int[] ptr;

        if (matchMemory != 0) {
            ptr = packet;
        } else {
            ptr = statusRegister;
        }

        switch (size) {
            case SDN_WISE_SIZE_2:
                return doOperation(operatore,
                        ptr[window.getPos()] * 256 + ptr[window.getPos() + 1],
                        window.getValueHigh() * 256 + window.getValueLow());
            case SDN_WISE_SIZE_1:
                return doOperation(operatore, ptr[window.getPos()], window.getValueLow());
            case SDN_WISE_SIZE_0:
                return 2;
            default:
                return 0;
        }
    }

    // Verifica che un pacchetto corrisponda a una regola
    int matchRule(FlowTableEntry rule, int[] packet) {
        int i;
        int sum = 0;
        for (i = 0; i < SDN_WISE_WINDOWS_MAX; i++) {
            int result = matchWindow(rule.getWindow()[i], packet);
            if (result != 0) {
                sum += result;
            } else {
                return 0;
            }
        }

        return (sum == SDN_WISE_WINDOWS_MAX * 2 ? 0 : 1);
    }

    // Esegue l'azione alla posizione r della tabella
    void runAction(FlowTableAction action, int[] packet) {

        int i;
        int action_type = action.getType();
        int action_location = action.getLocation();

        switch (action_type) {
            case SDN_WISE_FORWARD_UNICAST:
            case SDN_WISE_FORWARD_BROADCAST:
                packet[SDN_WISE_TTL]--;
                packet[action.getPos()] = action.getValueHigh();
                packet[action.getPos() + 1] = action.getValueLow();

                radioTX(packet, action_type == SDN_WISE_FORWARD_BROADCAST);
                break;

            case SDN_WISE_DROP:
                int prob = action.getValueHigh();
                // Se prob di drop=70% significa che se genero un numero,
                // droppo il pacchetto se il numero generato è inferiore a 70
                if ((Math.random() * 100) > prob) {

                    // il secondo  int indica il secondo  int
                    // dell'indirizzo del nodo a cui forwardare il pacchetto
                    // il primo  int è scelto casualmente, tra i vicini con
                    // il secondo  int dell'indirizzo posto uguale a quello
                    // contenuto nella rule
                    int first_byte_address = chooseNeighbor(action.getValueLow());
                    if (first_byte_address != 254) {
                        packet[SDN_WISE_TTL]--;
                        packet[SDN_WISE_NXHOP_H] = first_byte_address;
                        packet[SDN_WISE_NXHOP_L] = action.getValueHigh();
                        radioTX(packet, SDN_WISE_MAC_SEND_UNICAST);
                    }//else
                }//else
                break;
                //case 2
            case SDN_WISE_MODIFY:
                if (action_location != 0) {
                    int tmpAct1 = packet[action.getPos()];
                    int tmpAct2 = packet[action.getPos() + 1];
                    packet[action.getPos()] = action.getValueHigh();
                    packet[action.getPos() + 1] = action.getValueLow();
                    // TODO considerare il caso del multicas quando si inseriscono i  int[] nella messageQueue
                    messageQueue.add(packet);
                    packet[action.getPos()] = tmpAct1;
                    packet[action.getPos() + 1] = tmpAct2;
                } else {
                    statusRegister[action.getPos()] = action.getValueHigh();
                    statusRegister[action.getPos() + 1] = action.getValueLow();
                    messageQueue.add(packet);
                }
                break;
            case SDN_WISE_AGGREGATE:
                // TODO Ancora da definire
                break;
            case SDN_WISE_FORWARD_UP:
                FunctionInterface srvI
                        = functions.get(action.getValueHigh() * 256 + action.getValueLow());
                if (srvI != null) {
                    srvI.function(
                            adcRegister,
                            flowTable,
                            neighborTable,
                            statusRegister,
                            acceptedId,
                            messageQueue,
                            new NetworkPacket(packet)
                    );
                }
                break;
            default:
                break;
        }//switch
    }
    int doOperation(int operatore, int item1, int item2) {
        switch (operatore) {
            case SDN_WISE_EQUAL:
                return item1 == item2 ? 1 : 0;
            case SDN_WISE_NOT_EQUAL:
                return item1 != item2 ? 1 : 0;
            case SDN_WISE_BIGGER:
                return item1 > item2 ? 1 : 0;
            case SDN_WISE_LESS:
                return item1 < item2 ? 1 : 0;
            case SDN_WISE_EQUAL_OR_BIGGER:
                return item1 >= item2 ? 1 : 0;
            case SDN_WISE_EQUAL_OR_LESS:
                return item1 <= item2 ? 1 : 0;
            default:
                return 0;
        }
    }

    int searchRule(FlowTableEntry rule) {
        int i, j, sum, target;

        for (i = 0; i < SDN_WISE_RLS_MAX; i++) {
            sum = 0;
            target = SDN_WISE_WINDOWS_MAX;

            for (j = 0; j < SDN_WISE_WINDOWS_MAX; j++) {
                if (flowTable.get(i).getWindow()[j].getOp() == rule.getWindow()[j].getOp()
                        && flowTable.get(i).getWindow()[j].getPos() == rule.getWindow()[j].getPos()
                        && flowTable.get(i).getWindow()[j].getValueHigh() == rule.getWindow()[j].getValueHigh()
                        && flowTable.get(i).getWindow()[j].getValueLow() == rule.getWindow()[j].getValueLow()) {
                    sum++;
                }
            }

            if (rule.getAction().getMultimatch()) {
                target++;

                if (flowTable.get(i).getAction().getAct() == rule.getAction().getAct()
                        && flowTable.get(i).getAction().getPos() == rule.getAction().getPos()
                        && flowTable.get(i).getAction().getValueHigh() == rule.getAction().getValueHigh()
                        && flowTable.get(i).getAction().getValueLow() == rule.getAction().getValueLow()) {
                    sum++;
                }
            }

            if (sum == target) {
                return i;
            }
        }
        return SDN_WISE_RLS_MAX + 1;
    }

    int getNeighborIndex(NodeAddress addr) {
        int i;
        for (i = 0; i < SDN_WISE_NEIGHBORS_MAX; i++) {

            if (neighborTable.get(i).getAddr().equals(addr)) {
                return i;
            }
            if (neighborTable.get(i).getAddr().equals(new NodeAddress(255, 255))) { //se sono uguali
                return -1;
            }
        }
        return SDN_WISE_NEIGHBORS_MAX + 1;
    }

    int searchAcceptedId(int addr) {
        int i;
        for (i = 0; i < SDN_WISE_ACCEPTED_ID_MAX; i++) {
            if (acceptedId.get(i).intValue() == addr) {
                return i;
            }
        }
        return SDN_WISE_ACCEPTED_ID_MAX + 1;
    }

    boolean isAcceptedIdAddress(int addr_h, int addr_l) {
        return (addr_h == addr.getHigh()
                && addr_l == addr.getLow())
                || (addr_h == 255 && addr_l == 255)
                || (searchAcceptedId(new NodeAddress(addr_h, addr_l).intValue())
                != SDN_WISE_ACCEPTED_ID_MAX + 1);
    }

    boolean isAcceptedIdPacket(int[] packet) {
        return isAcceptedIdAddress(packet[SDN_WISE_DST_H], packet[SDN_WISE_DST_L]);
    }

    int getActualFlowIndex(int j) {
        //j = j % SDN_WISE_RLS_MAX;
        int i;
        if (j == 0) {
            i = 0;
        } else {
            i = flow_table_free_pos - j;
            if (i == 0) {
                i = SDN_WISE_RLS_MAX - 1;
            } else if (i < 0) {
                i = SDN_WISE_RLS_MAX - 1 + i;
            }
        }
        return i;
    }

    abstract void SDN_WISE_Callback(int[] packet);

    abstract void controllerTX(int[] packetInt);

    public void radioTX(int[] packetInt, boolean sdn_wise_mac_send_unicast) {
        battery.transmitRadio(packetInt.length);

        System.out.println("[N"+ addr.toString() +"]: RTX " + Arrays.toString(packetInt));

        NetworkPacket np = new NetworkPacket(packetInt);

        NodeAddress tmpNxHop = np.getNxhop();
        NodeAddress tmpDst = np.getDst();

        if (tmpDst.equals(new NodeAddress("255.255"))) {
            for (FakeInfo isa : neighbourList.values()) {
                DatagramPacket pck = new DatagramPacket(np.toByteArray(), np.getLen(),
                        isa.inetAddress.getAddress(), isa.inetAddress.getPort());
                try {
                    socket.send(pck);

                } catch (IOException ex) {
                    Logger.getLogger(Node.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        } else {
            FakeInfo isa = neighbourList.get(tmpNxHop);
            if (isa != null) {
                try {
                    DatagramPacket pck = new DatagramPacket(np.toByteArray(), np.getLen(),
                            isa.inetAddress.getAddress(), isa.inetAddress.getPort());
                    socket.send(pck);
                } catch (UnknownHostException ex) {
                    Logger.getLogger(SensorNode.class.getName()).log(Level.SEVERE, null, ex);
                } catch (IOException ex) {
                    Logger.getLogger(SensorNode.class.getName()).log(Level.SEVERE, null, ex);
                }
            }

        }
    }

    public void arraycopy(int[] src, int srcPos, byte[] dst, int dstPos, int len) {
        for (int i = 0; i < len; i++) {
            dst[dstPos + i] = (byte) src[srcPos + i];
        }
    }

    public void arraycopy(byte[] src, int srcPos, int[] dst, int dstPos, int len) {
        for (int i = 0; i < len; i++) {
            dst[dstPos + i] = src[srcPos + i];
        }
    }

    public FunctionInterface createServiceInterface(byte[] classFile) {
        CustomClassLoader cl = new CustomClassLoader();
        FunctionInterface srvI = null;
        Class service = cl.defClass(classFile, classFile.length);
        try {
            srvI = (FunctionInterface) service.newInstance();
        } catch (InstantiationException | IllegalAccessException ex) {
            Logger.getLogger(Node.class.getName()).log(Level.SEVERE, null, ex);
        }
        return srvI;
    }


    private class FakeInfo {

        InetSocketAddress inetAddress;
        int rssi;

        FakeInfo(InetSocketAddress inetAddress, int rssi) {
            this.inetAddress = inetAddress;
            this.rssi = rssi;
        }
    }

    private class Task extends TimerTask {

        private int cntBeacon;
        private int cntReport;
        private int cntUpdTable;

        @Override
        public void run() {
            if (semaphore == 1) {
                battery.keepAlive(1);

                cntBeacon++;
                cntReport++;
                //cntUpdTable++; // TODO IMBRACCHIO!!!!!!

                if ((cntBeacon) >= cnt_beacon_max) {
                    cntBeacon = 0;
                    txBEACON();
                }

                if ((cntReport) >= cnt_report_max) {
                    cntReport = 0;
                    txREPORT();
                }

                if ((cntUpdTable) >= cnt_updtable_max) {
                    cntUpdTable = 0;
                    updateTable();
                }
            }
        }

    }

    private class PacketManager implements Runnable {

        @Override
        public void run() {
            try {
                while (true) {
                    int rssi;
                    int[] tmp = messageQueue.take();
                    NetworkPacket tmpPacket = new NetworkPacket(tmp);
                    FakeInfo fk = neighbourList.get(tmpPacket.getSrc());
                    if (fk != null) {
                        rssi = fk.rssi;
                    } else {
                        rssi = 255;
                    }
                    battery.receiveRadio(tmp.length);
                    rxHandler(tmp, rssi);
                }
            } catch (InterruptedException ex) {
                Logger.getLogger(Node.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        public void rxHandler(int[] packet, int rssi) throws InterruptedException {
            System.out.println("[N"+ addr.toString() +"]: RRX " + Arrays.toString(packet));

            if (packet[SDN_WISE_LEN] > SDN_WISE_DFLT_HDR_LEN
                    && packet[SDN_WISE_NET_ID] == net_id
                    && packet[SDN_WISE_TTL] != 0) {

                switch (packet[SDN_WISE_TYPE]) {
                    case SDN_WISE_DATA:
                        rxDATA(packet);
                        break;

                    case SDN_WISE_BEACON:
                        rxBEACON(packet, rssi);
                        break;

                    case SDN_WISE_RESPONSE:
                        rxRESPONSE(packet);
                        break;

                    case SDN_WISE_OPEN_PATH:
                        rxOPEN_PATH(packet);
                        break;

                    case SDN_WISE_CONFIG:
                        rxCONFIG(packet);
                        break;

                    default:
                        rxREPORT(packet);
                        break;
                }// fine switch sul type
            }// fine if sull'address
        }
    }

    private class CustomClassLoader extends ClassLoader {

        public Class defClass(byte[] data, int len) {
            return defineClass(null, data, 0, len);
        }
    }


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy