view src/main/java/jp/ac/u_ryukyu/treevnc/TreeManagement.java @ 464:a817fa255673

fix onTheSame Network
author kono
date Tue, 12 Jul 2016 18:52:27 +0900
parents 5bef0f09f088
children f7210f834403
line wrap: on
line source

package jp.ac.u_ryukyu.treevnc;


import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.LinkedList;

public class TreeManagement {


    private final int treeId;
    public LinkedList<TreeVNCNode> nodeList = new LinkedList<TreeVNCNode>();
    public LinkedList<NetworkAddress> treeAddresses = new LinkedList<NetworkAddress>();
    private final int treebranch = 2;
    private boolean showTreeNode = false;
    //  node id
    //      ttttnnnnnnnnnnnn
    //      tttt          4bit tree number
    //     nnnnnnnnnnnn  12bit node number
    public final int MAX_TREE = 15;
    public final int MAX_TREE_NODE = (1<<12)-1;

    public TreeManagement(String hostName, int vncport, boolean showTree, int id) {
        treeId = id;
        TreeVNCNode me = new TreeVNCNode(hostName, vncport,"localhost");
        showTreeNode = showTree;
        me.setTreeNum(0);
        nodeList.add(me);
    }

    private class NetworkAddress {
        InetAddress inetaddress;
        byte [] address;
        byte [] netmask;

        public NetworkAddress(InetAddress ipaddress, byte[] netaddress, byte[] netmask) {
            inetaddress = ipaddress;
            address = netaddress;
            this.netmask = netmask;
        }
    }

    public int getTreeId() {
        return treeId;
    }

    /**
     * a parent is lost, remove from the list and move last one into here
     * @param nodeNum
     *            parent value
     */
    public void moveLastNodeToLostNodePosition(int nodeNum) {
        nodeList.remove(nodeNum);
        if (nodeNum != nodeList.size()) {
            TreeVNCNode node = nodeList.removeLast();
            node.setTreeNum(nodeNum);
            nodeList.add(nodeNum, node);
        }
    }

    private void checkParameter(int parent, int counter, int leaderflag2) {
        System.out.print("number p =" + parent);
        System.out.print(" number i =" + counter);
        System.out.println(" leaderflag=" + leaderflag2 + "\n");
    }

    private TreeVNCNode getParentNode(int nodeNum) {
        int parentnum = (nodeNum - 1) / treebranch;
        return  nodeList.get(parentnum);
    }


    public TreeVNCNode getChildNode(TreeVNCNode newparent, int i) {
        int child = newparent.getTreeNum() * treebranch + i + 1;
        if (child >= nodeList.size()) {
            return(null);
        } else {
            return(nodeList.get(child));
        }
    }

    /**
     * A parent is lost, move last node which has no child to the position 
     * @param hostname
     * @param port
     * @param myHostName 
     */
    public void fixLostParent(String hostname, int port, String myHostName) {
        TreeVNCNode lostParentNode = lookup(nodeList,hostname,port);
        if (lostParentNode == null ) return;   // something wrong
        int treeNumber = lostParentNode.getTreeNum();
        TreeVNCNode deadParent = getParentNode(treeNumber);
        TreeVNCNode me = nodeList.getFirst();
        me.setHostName(myHostName);
        if (deadParent.getTreeNum() == 0) {
            // if dead root, connect me.
            try {
                connectTo(me, lostParentNode);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return;
        }
        if (getChildNode(deadParent, 0) == null) return;
        moveLastNodeToLostNodePosition(deadParent.getTreeNum());
        lostNodeConnection(deadParent);
        // if lostParentNode is the last one, we don't need reconnection
        // Thread.sleep(intv_time);
    }

    public void fixLostChild(String hostname, int port, String myHostName, int clientId) {
        TreeVNCNode lostChildNode = lookup(nodeList, hostname, port);
        if (lostChildNode == null) return;
        int lostChildNodeNum;
        // if isTreeManager
        if (lostChildNode.getTreeNum() == 0) {
            lostChildNodeNum = clientId + 1;
        } else {
            lostChildNodeNum = (lostChildNode.getTreeNum() * treebranch) + clientId + 1;
        }
        TreeVNCNode deadChild;
        fixLostChild1(lostChildNodeNum);
    }

    public void fixLostChild1(int nodeNum) {
        TreeVNCNode deadNode;
        try {
            deadNode = nodeList.get(nodeNum);
        } catch (IndexOutOfBoundsException e) {
            // this node became new node instead of deathChild.
            deadNode = null;
        }
        if (deadNode != null) {
            moveLastNodeToLostNodePosition(deadNode.getTreeNum());
            lostNodeConnection(deadNode);
        }
        if (showTreeNode) {
            showTreeNode();
        }
    }

    /**
     * send reconnect to all children
     * @param deadNode
     */
    public void lostNodeConnection(TreeVNCNode deadNode) {
        if (nodeList.size() < deadNode.getTreeNum()+1) {
            return;
        }
        TreeVNCNode newNode = nodeList.get(deadNode.getTreeNum());
        TreeVNCNode parentNode = getParentNode(newNode.getTreeNum());
        // new node connect to parent node.
        try {
            connectTo(parentNode, newNode);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // if children node exist, children connect to new node.
        for(int i=0; i < treebranch; i++) {
            TreeVNCNode child = getChildNode(newNode, i);
            if (child != null) {
                try {
                    connectTo(newNode, child);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public void connectTo(TreeVNCNode newparent, TreeVNCNode n) throws IOException {
        TreeVncProtocol vc1 = new TreeVncProtocol(n.getHostname(),n.getPort());
            short nodeId = (short) ( n.getTreeNum() + ( treeId << 12 ));
            vc1.connectTo(newparent.getHostname(), newparent.getPort(), isLeader(n), nodeId);
    }

    private int isLeader(TreeVNCNode n) {
        return ( n.getTreeNum() % treebranch == 1) ? 1 : 0;
    }

    private TreeVNCNode lookup(LinkedList<TreeVNCNode> list, String hostname, int port) {
        for (TreeVNCNode r : list) {
            if (r.getHostname().equals(hostname) && r.getPort() == port )
                return r;
        }
        return null;
    }

    /**
     * Determine tree topology and send CONNECT_TO command
     * @param hostname
     * @param port
     */
    public void decideWhereToConnect(String hostname, int port, String localhostname) {
        TreeVNCNode node = new TreeVNCNode(hostname, port, localhostname);
        node.setTreeNum(nodeList.size());

        InetAddress ipAddress = null;
        try {
            ipAddress = InetAddress.getByName(hostname);
        } catch (UnknownHostException e) {
            System.out.println("root : whereToConnect : cannot get ipAddress" + hostname);
            return;
        }
        if (onTheSameNetwork(ipAddress))
            nodeList.add(node);
        if (nodeList.size() >= treebranch + 1) {
            TreeVNCNode parent = getParentNode(node.getTreeNum());
            checkParameter(parent.getTreeNum(), nodeList.size(), isLeader(node));
            try {
                connectTo(parent, node);
            } catch (IOException e) {
                nodeList.remove(node);
                System.out.println("root : whereToConnect : Connection Faild" + hostname);
                return;
            }
        } else {
            // connect to me
            TreeVNCNode me = nodeList.getFirst();
            me.setHostName(localhostname);
            try {
                connectTo(me, node);
            } catch (IOException e) {
                nodeList.remove(node);
                System.out.println("root : whereToConnect : Connection Faild" + hostname);
                return;
            }
        }
        if (showTreeNode) {
            showTreeNode();
        }
    }

    /**
     * show Tree Node.
     */
    public void showTreeNode() {
        int nl = 0, pow = 2;
        for (int i=0; i<nodeList.size(); i++) {
            TreeVNCNode treeNode = nodeList.get(i);
            System.out.print(treeNode.getTreeNum() + ":" + treeNode.getPort() + ":" + treeNode.getHostname());
            if (i==nl) {
                System.out.println();
                nl = nl + pow;
                pow = pow * pow;
            } else {
                System.out.print(" ");
            }

        }
        System.out.println();
    }

    public LinkedList<TreeVNCNode> getList() {
        return nodeList;
    }

    public void setList(LinkedList<TreeVNCNode> _ls) {
        nodeList = _ls;
    }

    public int getTreeBranch() {
        return treebranch;
    }

    public void setNetMask(byte[] netmask, byte[] netaddress, InetAddress ipaddress) {
        treeAddresses.add(new NetworkAddress(ipaddress,netaddress,netmask) );
    }

    public boolean onTheSameNetwork(InetAddress adr) {
        byte [] byteadr = adr.getAddress();
        for (NetworkAddress n : treeAddresses) {
            byte [] netmask = n.netmask;
            byte [] netaddress = n.address;
            if (byteadr.length != netmask.length) continue;
            int i;
            for (i = 0; i < netmask.length; i++) {
                if ((netmask[i] & byteadr[i]) != netaddress[i]) break;
            }
            if (i < netmask.length) continue;
            return true;
        }
        return false;
    }
}