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

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

There is a newer version: 2.0.13
Show newest version
/*
 * 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.*;
import static com.github.sdnwiselab.sdnwise.flowtable.SetAction.*;
import static com.github.sdnwiselab.sdnwise.flowtable.Stats.SDN_WISE_RL_TTL_PERMANENT;
import static com.github.sdnwiselab.sdnwise.flowtable.Window.*;
import com.github.sdnwiselab.sdnwise.function.FunctionInterface;
import static com.github.sdnwiselab.sdnwise.node.Constants.*;
import com.github.sdnwiselab.sdnwise.packet.*;
import static com.github.sdnwiselab.sdnwise.packet.ConfigAcceptedIdPacket.*;
import static com.github.sdnwiselab.sdnwise.packet.ConfigFunctionPacket.*;
import static com.github.sdnwiselab.sdnwise.packet.ConfigNodePacket.*;
import static com.github.sdnwiselab.sdnwise.packet.ConfigRulePacket.*;
import static com.github.sdnwiselab.sdnwise.packet.ConfigTimerPacket.*;
import static com.github.sdnwiselab.sdnwise.packet.NetworkPacket.*;
import com.github.sdnwiselab.sdnwise.util.*;
import java.io.*;
import java.net.*;
import java.nio.file.*;
import java.util.*;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.logging.*;

/**
 *
 * @author Sebastiano Milardo
 */
public abstract class Node implements Runnable {

    private static final Logger LOGGER = Logger.getLogger(Node.class.getName());

    /**
     * @param args the command line arguments
     */
    private int sentBytes;
    private int receivedBytes;
    private int distanceFromSink;
    private int rssiSink;

    private final byte[] buf;

    final ArrayBlockingQueue flowTableQueue;
    final ArrayBlockingQueue txQueue;

    int port,
            semaphore,
            flow_table_free_pos,
            accepted_id_free_pos,
            neighbors_number,
            net_id,
            cnt_beacon_max,
            cnt_report_max,
            cnt_updtable_max,
            cnt_sleep_max,
            ttl_max,
            rssi_min;

    NodeAddress addr;
    DatagramSocket socket;
    String neighborFilePath;
    String logFilePath;
    Battery battery;
    ArrayList neighborTable;
    ArrayList flowTable;
    ArrayList acceptedId;

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

    public ArrayList statusRegister = new ArrayList<>();

    public Node(NodeAddress addr, byte net_id, int port, String neighborFilePath, String log, String level) {
        buf = new byte[NetworkPacket.SDN_WISE_MAX_LEN];
        logFilePath = log;
        neighborTable = new ArrayList<>(SDN_WISE_NEIGHBORS_MAX);
        acceptedId = new ArrayList<>(SDN_WISE_ACCEPTED_ID_MAX);
        flowTable = new ArrayList<>(0);
        flowTableQueue = new ArrayBlockingQueue<>(1024);
        txQueue = new ArrayBlockingQueue<>(1024);
        this.addr = addr;
        this.net_id = net_id;
        this.neighborFilePath = neighborFilePath;
        this.neighbourList = new HashMap<>();
        this.port = port;
        LOGGER.setLevel(Level.parse(level));
        FileHandler fh;  
        try {
            fh = new FileHandler(addr + ".log");
            fh.setFormatter(new SimpleFormatter());
            LOGGER.addHandler(fh);
            LOGGER.setUseParentHandlers(false);
        } catch (IOException | SecurityException ex) {
            LOGGER.log(Level.SEVERE, null, ex);
        }
        setup();
    }

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

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

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

    public final int getNum_hop_vs_sink() {
        return distanceFromSink;
    }

    public final int getRssi_vs_sink() {
        return rssiSink;
    }

    public final int getSemaphore() {
        return semaphore;
    }

    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;
        try {
            is = new FileInputStream(neighborFilePath);
        } catch (FileNotFoundException ex) {
            LOGGER.log(Level.INFO, "External Config file not found, using embedded one {0}", neighborFilePath);
            is = this.getClass().getResourceAsStream("/" + neighborFilePath);
        }

        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 (IOException ex) {
            LOGGER.log(Level.SEVERE, null, ex);
        }
    }

    public void initFlowTable() {
        for (int i = 0; i < SDN_WISE_RLS_MAX; i++) {
            flowTable.add(i, new FlowTableEntry());
        }
        flowTable.get(0).addWindow(new Window()
                .setOperator(SDN_WISE_EQUAL)
                .setSize(SDN_WISE_SIZE_2)
                .setLhsLocation(SDN_WISE_PACKET)
                .setLhs(SDN_WISE_DST_H)
                .setRhsLocation(SDN_WISE_CONST)
                .setRhs(0));
        flowTable.get(0).addWindow(Window.fromString("P.TYPE != 0"));
        flowTable.get(0).addAction(ActionBuilder.build("FORWARD_U 0"));
        flowTable.get(0).setStats(new Stats());
    }

    public final void rxReport(ReportPacket packet) {
        controllerTX(packet);
    }

    @Override
    public final void run() {
        try {
            DatagramPacket packet = new DatagramPacket(buf, buf.length);
            socket = new DatagramSocket(port);
            new Timer().schedule(new Task(), 1000, 1000);
            // Enable for extensive logging
            if (logFilePath != null) {
                try {
                    Files.deleteIfExists(FileSystems.getDefault()
                            .getPath("", logFilePath));
                } catch (IOException ex) {
                    // File permission problems are caught here.
                    LOGGER.log(Level.SEVERE, null, ex);
                }
                new Timer().schedule(new TaskLogger(), 1000, 1000);
            }
            new Thread(new PacketManager()).start();
            new Thread(new PacketSender()).start();
            while (true) {
                socket.receive(packet);
                NetworkPacket np = new NetworkPacket(packet.getData());
                flowTableQueue.put(np);
            }
        } catch (IOException | InterruptedException ex) {
            LOGGER.log(Level.SEVERE, null, ex);
        }
    }

    public final void radioTX(NetworkPacket np, boolean sdn_wise_mac_send_unicast) {

        sentBytes += np.getLen();
        battery.transmitRadio(np.getLen());
        np.decrementTtl();
        LOGGER.log(Level.FINE,
                "[{0}]: RTX {1}", new Object[]{addr.toString(), np});
        NodeAddress tmpNxHop = np.getNxhop();
        NodeAddress tmpDst = np.getDst();
        if (tmpDst.isBroadcast()) {
            for (FakeInfo isa : neighbourList.values()) {
                DatagramPacket pck = new DatagramPacket(np.toByteArray(),
                        np.getLen(), isa.inetAddress);
                try {
                    socket.send(pck);
                } catch (IOException ex) {
                    LOGGER.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);
                    socket.send(pck);
                } catch (IOException ex) {
                    LOGGER.log(Level.SEVERE, null, ex);
                }
            }
        }
    }

    public final 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.log(Level.SEVERE, null, ex);
        }
        return srvI;
    }

    public final NodeAddress NxHopVsSink() {
        return ((AbstractForwardAction) (flowTable.get(0).getActions().get(0))).getNextHop();
    }

    public final void rxData(DataPacket packet) {
        if (isAcceptedIdPacket(packet)) {
            SDN_WISE_Callback(packet);
        } else if (isAcceptedIdAddress(packet.getNxhop())) {
            runFlowMatch(packet);
        }
    }

    public void rxBeacon(BeaconPacket bp, int rssi) {
        int index = getNeighborIndex(bp.getSrc());

        if (index != (SDN_WISE_NEIGHBORS_MAX + 1)) {
            if (index != -1) {
                neighborTable.get(index).setRssi(rssi);
                neighborTable.get(index).setBatt(bp.getBatt());
            } else {
                neighborTable.get(neighbors_number).setAddr(bp.getSrc());
                neighborTable.get(neighbors_number).setRssi(rssi);
                neighborTable.get(neighbors_number).setBatt(bp.getBatt());
                neighbors_number++;
            }
        }
    }

    public void rxResponse(ResponsePacket rp) {
        if (isAcceptedIdPacket(rp)) {
            rp.getRule().setStats(new Stats());
            insertRule(rp.getRule(), searchRule(rp.getRule()));
        } else {
            runFlowMatch(rp);
        }
    }

    public void rxOpenPath(OpenPathPacket opp) {
        if (isAcceptedIdPacket(opp)) {
            List path = opp.getPath();
            for (int i = 0; i < path.size(); i++) {
                NodeAddress actual = path.get(i);
                if (isAcceptedIdAddress(actual)) {
                    if (i != 0) {
                        FlowTableEntry rule = new FlowTableEntry();
                        rule.addWindow(new Window()
                                .setOperator(SDN_WISE_EQUAL)
                                .setSize(SDN_WISE_SIZE_2)
                                .setLhsLocation(SDN_WISE_PACKET)
                                .setLhs(SDN_WISE_SRC_H)
                                .setRhsLocation(SDN_WISE_CONST)
                                .setRhs(path.get(path.size() - 1).intValue()));

                        rule.addWindow(new Window()
                                .setOperator(SDN_WISE_EQUAL)
                                .setSize(SDN_WISE_SIZE_2)
                                .setLhsLocation(SDN_WISE_PACKET)
                                .setLhs(SDN_WISE_DST_H)
                                .setRhsLocation(SDN_WISE_CONST)
                                .setRhs(this.getActualSinkAddress().intValue()));

                        rule.getWindows().addAll(opp.getOptionalWindows());

                        rule.addAction(new ForwardUnicastAction()
                                .setNextHop(path.get(i - 1))
                        );
                        int p = searchRule(rule);
                        insertRule(rule, p);
                    }

                    if (i != (path.size() - 1)) {
                        FlowTableEntry rule = new FlowTableEntry();

                        rule.addWindow(new Window()
                                .setOperator(SDN_WISE_EQUAL)
                                .setSize(SDN_WISE_SIZE_2)
                                .setLhsLocation(SDN_WISE_PACKET)
                                .setLhs(SDN_WISE_DST_H)
                                .setRhsLocation(SDN_WISE_CONST)
                                .setRhs(path.get(path.size() - 1).intValue()));

                        rule.addWindow(new Window()
                                .setOperator(SDN_WISE_EQUAL)
                                .setSize(SDN_WISE_SIZE_2)
                                .setLhsLocation(SDN_WISE_PACKET)
                                .setLhs(SDN_WISE_SRC_H)
                                .setRhsLocation(SDN_WISE_CONST)
                                .setRhs(this.getActualSinkAddress().intValue()));

                        rule.getWindows().addAll(opp.getOptionalWindows());

                        rule.addAction(new ForwardUnicastAction()
                                .setNextHop(path.get(i + 1))
                        );

                        int p = searchRule(rule);
                        insertRule(rule, p);
                        opp.setDst(path.get(i + 1));
                        opp.setNxhop(path.get(i + 1));

                        radioTX(opp, SDN_WISE_MAC_SEND_UNICAST);
                        break;
                    }
                }
            }
        } else {
            runFlowMatch(opp);
        }
    }

    public final void runFlowMatch(NetworkPacket 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) {
                LOGGER.log(Level.INFO, "[{0}]: Matched Rule #{1} {2}",
                        new Object[]{addr, j, flowTable.get(i).toString()});
                found = 1;
                for (AbstractAction a : flowTable.get(i).getActions()) {
                    runAction(a, packet);
                }
                flowTable.get(i).getStats()
                        .setCounter(flowTable.get(i).getStats().getCounter() + 1);
                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.setSrc(addr)
                    .setRequestFlag()
                    .setTtl(SDN_WISE_DFLT_TTL_MAX);
            controllerTX(packet);
        }
    }

    public abstract void rxConfig(ConfigPacket packet);

    public final void insertRule(FlowTableEntry rule, int pos) {
        if (pos >= SDN_WISE_RLS_MAX) {
            pos = flow_table_free_pos;
            flow_table_free_pos++;
            if (flow_table_free_pos >= SDN_WISE_RLS_MAX) {
                flow_table_free_pos = 1;
            }
        }
        LOGGER.log(Level.INFO, "[{0}]: Inserting rule {1} at position {2}",
                new Object[]{addr, rule, pos});
        flowTable.set(pos, rule);
    }

    public final int searchRule(FlowTableEntry rule) {
        int i, j, sum, target;
        for (i = 0; i < SDN_WISE_RLS_MAX; i++) {
            sum = 0;
            target = rule.getWindows().size();
            if (flowTable.get(i).getWindows().size() == target) {
                for (j = 0; j < rule.getWindows().size(); j++) {
                    if (flowTable.get(i).getWindows().get(j).equals(rule.getWindows().get(j))) {
                        sum++;
                    }
                }
            }
            if (sum == target) {
                return i;
            }
        }
        return SDN_WISE_RLS_MAX + 1;
    }

    public final boolean isAcceptedIdAddress(NodeAddress addrP) {
        return (addrP.equals(addr)
                || addrP.isBroadcast()
                || (searchAcceptedId(addrP)
                != SDN_WISE_ACCEPTED_ID_MAX + 1));
    }

    public final boolean isAcceptedIdPacket(NetworkPacket packet) {
        return isAcceptedIdAddress(packet.getDst());
    }

    public final NodeAddress getActualAddress() {
        return addr;
    }

    public final int getActualNetId() {
        return net_id;
    }

    public NodeAddress getActualSinkAddress() {
        return new NodeAddress(flowTable.get(0).getWindows().get(0).getRhs());
    }

    public abstract void SDN_WISE_Callback(DataPacket packet);

    public abstract void controllerTX(NetworkPacket pck);

    public int marshalPacket(ConfigPacket packet) {
        int toBeSent = 0;
        int pos;
        boolean isWrite = packet.isWrite();
        int id = packet.getConfigId();
        int value = packet.getPayloadAt(1) * 256 + packet.getPayloadAt(2);
        if (isWrite) {
            switch (id) {
                case SDN_WISE_CNF_ID_ADDR:
                    addr = new NodeAddress(value);
                    break;
                case SDN_WISE_CNF_ID_NET_ID:
                    net_id = packet.getPayloadAt(2);
                    break;
                case SDN_WISE_CNF_ID_CNT_BEACON_MAX:
                    cnt_beacon_max = value;
                    break;
                case SDN_WISE_CNF_ID_CNT_REPORT_MAX:
                    cnt_report_max = value;
                    break;
                case SDN_WISE_CNF_ID_CNT_UPDTABLE_MAX:
                    cnt_updtable_max = value;
                    break;
                case SDN_WISE_CNF_ID_CNT_SLEEP_MAX:
                    cnt_sleep_max = value;
                    break;
                case SDN_WISE_CNF_ID_TTL_MAX:
                    ttl_max = packet.getPayloadAt(2);
                    break;
                case SDN_WISE_CNF_ID_RSSI_MIN:
                    rssi_min = packet.getPayloadAt(2);
                    break;
                case SDN_WISE_CNF_ADD_ACCEPTED:
                    pos = searchAcceptedId(new NodeAddress(value));
                    if (pos == (SDN_WISE_ACCEPTED_ID_MAX + 1)) {
                        pos = searchAcceptedId(new NodeAddress(65535));
                        acceptedId.set(pos, new NodeAddress(value));
                    }
                    break;
                case SDN_WISE_CNF_REMOVE_ACCEPTED:
                    pos = searchAcceptedId(new NodeAddress(value));
                    if (pos != (SDN_WISE_ACCEPTED_ID_MAX + 1)) {
                        acceptedId.set(pos, new NodeAddress(65535));
                    }
                    break;
                case SDN_WISE_CNF_REMOVE_RULE_INDEX:
                    if (value != 0) {
                        flowTable.set(getActualFlowIndex(value), new FlowTableEntry());
                    }
                    break;
                case SDN_WISE_CNF_REMOVE_RULE:
                    //TODO
                    break;
                case SDN_WISE_CNF_ADD_FUNCTION:
                    if (functionBuffer.get(value) == null) {
                        functionBuffer.put(value, new LinkedList());
                    }
                    functionBuffer.get(value).add(Arrays.copyOfRange(
                            packet.toIntArray(), SDN_WISE_DFLT_HDR_LEN + 5,
                            packet.getLen()));
                    if (functionBuffer.get(value).size() == packet.getPayloadAt(4)) {
                        int total = 0;
                        for (int[] n : functionBuffer.get(value)) {
                            total += (n.length);
                        }
                        int pointer = 0;
                        byte[] func = new byte[total];
                        for (int[] n : functionBuffer.get(value)) {
                            for (int j = 0; j < n.length; j++) {
                                func[pointer] = (byte) n[j];
                                pointer++;
                            }
                        }
                        functions.put(value, createServiceInterface(func));
                        LOGGER.log(Level.INFO, "[{0}]: New Function Added - {1}",
                                new Object[]{addr.toString(), value});
                        functionBuffer.remove(value);
                    }
                    break;
                case SDN_WISE_CNF_REMOVE_FUNCTION:
                    functions.remove(value);
                    break;
                default:
                    break;
            }
        } else {
            toBeSent = 1;
            switch (id) {
                case SDN_WISE_CNF_ID_ADDR:
                    packet.setPayloadAt(addr.getHigh(), 1);
                    packet.setPayloadAt(addr.getLow(), 2);
                    break;
                case SDN_WISE_CNF_ID_NET_ID:
                    packet.setPayloadAt((byte) net_id, 2);
                    break;
                case SDN_WISE_CNF_ID_CNT_BEACON_MAX:
                    packet.setPayloadAt((byte) (cnt_beacon_max >> 8), 1);
                    packet.setPayloadAt((byte) (cnt_beacon_max), 2);
                    break;
                case SDN_WISE_CNF_ID_CNT_REPORT_MAX:
                    packet.setPayloadAt((byte) (cnt_report_max >> 8), 1);
                    packet.setPayloadAt((byte) (cnt_report_max), 2);
                    break;
                case SDN_WISE_CNF_ID_CNT_UPDTABLE_MAX:
                    packet.setPayloadAt((byte) (cnt_updtable_max >> 8), 1);
                    packet.setPayloadAt((byte) (cnt_updtable_max), 2);
                    break;
                case SDN_WISE_CNF_ID_CNT_SLEEP_MAX:
                    packet.setPayloadAt((byte) (cnt_sleep_max >> 8), 1);
                    packet.setPayloadAt((byte) (cnt_sleep_max), 2);
                    break;
                case SDN_WISE_CNF_ID_TTL_MAX:
                    packet.setPayloadAt((byte) ttl_max, 2);
                    break;
                case SDN_WISE_CNF_ID_RSSI_MIN:
                    packet.setPayloadAt((byte) rssi_min, 2);
                    break;
                case SDN_WISE_CNF_LIST_ACCEPTED:
                    toBeSent = 0;
                    ConfigAcceptedIdPacket packetList
                            = new ConfigAcceptedIdPacket(
                                    net_id,
                                    packet.getDst(),
                                    packet.getSrc());
                    packetList.setReadAcceptedAddressesValue();
                    int ii = 1;

                    for (int jj = 0; jj < SDN_WISE_ACCEPTED_ID_MAX; jj++) {
                        if (!acceptedId.get(jj).equals(new NodeAddress(65535))) {
                            packetList.setPayloadAt((acceptedId.get(jj)
                                    .getHigh()), ii);
                            ii++;
                            packetList.setPayloadAt((acceptedId.get(jj)
                                    .getLow()), ii);
                            ii++;
                        }
                    }
                    controllerTX(packetList);
                    break;
                case SDN_WISE_CNF_GET_RULE_INDEX:
                    toBeSent = 0;
                    ConfigRulePacket packetRule = new ConfigRulePacket(
                            net_id,
                            packet.getDst(),
                            packet.getSrc()
                    );
                    int jj = getActualFlowIndex(value);
                    packetRule.setRule(flowTable.get(jj))
                            .setPayloadAt(SDN_WISE_CNF_GET_RULE_INDEX, 0)
                            .setPayloadAt(packet.getPayloadAt(1), 1)
                            .setPayloadAt(packet.getPayloadAt(2), 2);
                    controllerTX(packetRule);
                    break;
                default:
                    break;
            }
        }
        return toBeSent;
    }

    public void rxHandler(NetworkPacket packet, int rssi) throws InterruptedException {
        LOGGER.log(Level.FINE, "[{0}]: RRX {1}",
                new Object[]{addr.toString(), packet});

        if (packet.getLen() > SDN_WISE_DFLT_HDR_LEN
                && packet.getNetId() == net_id
                && packet.getTtl() != 0) {

            switch (packet.getType()) {
                case SDN_WISE_DATA:
                    rxData(new DataPacket(packet));
                    break;

                case SDN_WISE_BEACON:
                    rxBeacon(new BeaconPacket(packet), rssi);
                    break;

                case SDN_WISE_REPORT:
                    rxReport(new ReportPacket(packet));
                    break;

                case SDN_WISE_RESPONSE:
                    rxResponse(new ResponsePacket(packet));
                    break;

                case SDN_WISE_OPEN_PATH:
                    rxOpenPath(new OpenPathPacket(packet));
                    break;

                case SDN_WISE_CONFIG:
                    rxConfig(new ConfigPacket(packet));
                    break;

                default:
                    runFlowMatch(packet);
                    break;
            }
        }
    }

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

    private void initStatusRegister() {
        for (int i = 0; i < SDN_WISE_STATUS_LEN; i++) {
            statusRegister.add(0);
        }
    }

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

    private void setup() {
        initSdnWise();
        initFlowTable();
        initNeighborTable();
        initAcceptedId();
        initStatusRegister();
    }

    private int getOperand(NetworkPacket packet, int size, int location, int value) {
        int[] intPacket = packet.toIntArray();
        switch (location) {
            case SDN_WISE_NULL:
                return 0;
            case SDN_WISE_CONST:
                return value;
            case SDN_WISE_PACKET:
                if (size == SDN_WISE_SIZE_1) {
                    if (value >= intPacket.length) {
                        LOGGER.log(Level.INFO, "{0} {1}", new Object[]{value, packet.toString()});
                        LOGGER.log(Level.WARNING, "Checking out of bounds");
                        return -1;
                    }
                    return intPacket[value];
                }
                if (size == SDN_WISE_SIZE_2) {
                    if (value + 1 >= intPacket.length) {
                        LOGGER.log(Level.INFO, "{0} {1}", new Object[]{value, packet.toString()});
                        LOGGER.log(Level.WARNING, "Checking out of bounds");
                        return -1;
                    }
                    return Utils.mergeBytes(intPacket[value], intPacket[value + 1]);
                }
            case SDN_WISE_STATUS:
                if (size == SDN_WISE_SIZE_1) {
                    if (value >= statusRegister.size()) {
                        LOGGER.log(Level.INFO, "Checking status at position {0}", value);
                        LOGGER.log(Level.WARNING, "Checking out of bounds");
                        return -1;
                    }
                    return statusRegister.get(value);
                }
                if (size == SDN_WISE_SIZE_2) {
                    if (value + 1 >= statusRegister.size()) {
                        LOGGER.log(Level.INFO, "Checking out of bounds");
                        LOGGER.log(Level.WARNING, "Checking out of bounds");
                        return -1;
                    }
                    return Utils.mergeBytes(
                            statusRegister.get(value),
                            statusRegister.get(value + 1));
                }
        }
        return -1;
    }

    // Verifica che una condizione di una finestra di una regola è soddisfatta
    private int matchWindow(Window window, NetworkPacket packet) {
        int operator = window.getOperator();
        int size = window.getSize();
        int lhs = getOperand(
                packet, size, window.getLhsLocation(), window.getLhs());
        int rhs = getOperand(
                packet, size, window.getRhsLocation(), window.getRhs());
        return compare(operator, lhs, rhs);
    }

    // Verifica che un pacchetto corrisponda a una regola
    private int matchRule(FlowTableEntry rule, NetworkPacket packet) {
        if (rule.getWindows().isEmpty()) {
            return 0;
        }

        int target = rule.getWindows().size();
        int actual = 0;

        for (Window w : rule.getWindows()) {
            actual = actual + matchWindow(w, packet);
        }
        return (actual == target ? 1 : 0);
    }

    // Esegue l'azione alla posizione r della tabella
    private void runAction(AbstractAction action, NetworkPacket np) {
        try {
            int action_type = action.getType();

            switch (action_type) {
                case SDN_WISE_FORWARD_U:
                case SDN_WISE_FORWARD_B:
                    np.setNxhop(((AbstractForwardAction) action).getNextHop());
                    radioTX(np, action_type == SDN_WISE_FORWARD_B);
                    break;

                case SDN_WISE_DROP:
                    break;
                //case 2
                case SDN_WISE_SET:
                    SetAction ftam = (SetAction) action;
                    int operator = ftam.getOperator();
                    int lhs = getOperand(
                            np, SDN_WISE_SIZE_1, ftam.getLhsLocation(), ftam.getLhs());
                    int rhs = getOperand(
                            np, SDN_WISE_SIZE_1, ftam.getRhsLocation(), ftam.getRhs());

                    if (lhs == -1 || rhs == -1) {
                        throw new IllegalArgumentException("Operators out of bound");
                    }

                    int res = doOperation(operator, lhs, rhs);

                    if (ftam.getResLocation() == SDN_WISE_PACKET) {
                        int[] packet = np.toIntArray();

                        if (ftam.getRes() >= packet.length) {
                            throw new IllegalArgumentException("Result out of bound");
                        }

                        packet[ftam.getRes()] = res;
                        np.setArray(packet);
                    } else {
                        statusRegister.set(ftam.getRes(), res);
                    }
                    break;
                case SDN_WISE_FUNCTION:
                    FunctionAction ftac = (FunctionAction) action;
                    FunctionInterface srvI = functions.get(ftac.getCallbackId());
                    if (srvI != null) {
                        LOGGER.log(Level.INFO, "[{0}]: function called", addr);
                        srvI.function(adcRegister,
                                flowTable,
                                neighborTable,
                                statusRegister,
                                acceptedId,
                                flowTableQueue,
                                txQueue,
                                ftac.getArg0(),
                                ftac.getArg1(),
                                ftac.getArg2(),
                                np
                        );
                    }
                    break;
                case SDN_WISE_ASK:
                    np.setSrc(addr)
                            .setRequestFlag()
                            .setTtl(NetworkPacket.SDN_WISE_DFLT_TTL_MAX);
                    controllerTX(np);
                    break;
                case SDN_WISE_MATCH:
                    flowTableQueue.add(np);
                    break;
                case SDN_WISE_TO_UDP:
                    ToUdpAction tua = (ToUdpAction) action;
                    DatagramSocket sUDP = new DatagramSocket();
                    DatagramPacket pck = new DatagramPacket(np.toByteArray(),
                            np.getLen(), tua.getInetSocketAddress());
                    sUDP.send(pck);
                    break;
                default:
                    break;
            }//switch
        } catch (IOException ex) {
            LOGGER.log(Level.SEVERE, null, ex);
        }
    }

    private int doOperation(int operatore, int item1, int item2) {
        switch (operatore) {
            case SDN_WISE_ADD:
                return item1 + item2;
            case SDN_WISE_SUB:
                return item1 - item2;
            case SDN_WISE_DIV:
                return item1 / item2;
            case SDN_WISE_MUL:
                return item1 * item2;
            case SDN_WISE_MOD:
                return item1 % item2;
            default:
                return 0;
        }
    }

    private int compare(int operatore, int item1, int item2) {
        if (item1 == -1 || item2 == -1) {
            return 0;
        }
        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;
        }
    }

    void resetSemaphore() {
    }

    BeaconPacket prepareBeacon() {
        BeaconPacket bp = new BeaconPacket(
                net_id,
                addr,
                getActualSinkAddress(),
                distanceFromSink,
                battery.getBatteryPercent());
        return bp;
    }

    ReportPacket prepareReport() {

        ReportPacket rp = new ReportPacket(
                net_id,
                addr,
                getActualSinkAddress(),
                distanceFromSink,
                battery.getBatteryPercent());

        rp.setNeigh(neighbors_number)
                .setNxhop(NxHopVsSink());

        for (int j = 0; j < neighbors_number; j++) {
            rp.setNeighbourAddressAt(neighborTable.get(j).getAddr(), j)
                    .setNeighbourWeightAt((byte) neighborTable.get(j).getRssi(), j);
        }
        initNeighborTable();
        return rp;
    }

    final void updateTable() {
        for (int i = 0; i < SDN_WISE_RLS_MAX; i++) {
            FlowTableEntry tmp = flowTable.get(i);
            if (tmp.getWindows().size() > 1) {
                int ttl = tmp.getStats().getTtl();
                if (ttl != SDN_WISE_RL_TTL_PERMANENT) {
                    if (ttl >= SDN_WISE_RL_TTL_DECR) {
                        tmp.getStats().decrementTtl(SDN_WISE_RL_TTL_DECR);
                    } else {
                        flowTable.set(i, new FlowTableEntry());
                        LOGGER.log(Level.INFO,
                                "[{0}]: Removing rule at position {1}", new Object[]{addr, i});
                        if (i == 0) {
                            resetSemaphore();
                        }
                    }
                }
            }
        }
    }

    final 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().isBroadcast()) {
                return -1;
            }
        }
        return SDN_WISE_NEIGHBORS_MAX + 1;
    }

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

    final 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;
    }

    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.getBatteryLevel() > 0) {
                battery.keepAlive(1);

                cntBeacon++;
                cntReport++;
                //cntUpdTable++; // TODO will be enabled again in the future

                if ((cntBeacon) >= cnt_beacon_max) {
                    cntBeacon = 0;
                    radioTX(prepareBeacon(), SDN_WISE_MAC_SEND_BROADCAST);
                }

                if ((cntReport) >= cnt_report_max) {
                    cntReport = 0;
                    controllerTX(prepareReport());
                }

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

    private class TaskLogger extends TimerTask {

        @Override
        public void run() {
            try (PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(logFilePath, true)))) {
                out.println((int) battery.getBatteryLevel() + ","
                        + battery.getBatteryPercent() + ","
                        + flow_table_free_pos + ","
                        + sentBytes + ","
                        + receivedBytes);
            } catch (IOException ex) {
                LOGGER.log(Level.SEVERE, null, ex);
            }
        }
    }

    private class PacketSender implements Runnable {

        @Override
        public void run() {
            try {
                while (true) {
                    radioTX(txQueue.take(), SDN_WISE_MAC_SEND_UNICAST);
                }
            } catch (InterruptedException ex) {
                LOGGER.log(Level.SEVERE, null, ex);
            }
        }
    }

    private class PacketManager implements Runnable {

        @Override
        public void run() {
            try {
                while (battery.getBatteryLevel() > 0) {
                    int rssi;
                    NetworkPacket tmpPacket = flowTableQueue.take();
                    FakeInfo fk = neighbourList.get(tmpPacket.getSrc());
                    if (fk != null) {
                        rssi = fk.rssi;
                    } else {
                        rssi = 255;
                    }
                    battery.receiveRadio(tmpPacket.getLen());
                    receivedBytes += tmpPacket.getLen();

                    rxHandler(tmpPacket, rssi);
                }
            } catch (InterruptedException ex) {
                LOGGER.log(Level.SEVERE, null, ex);
            }
        }
    }

    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