/** * @copyright 2013 Computer Science Department, Recursive InterNetworking Architecture (RINA) laboratory, Boston University. * All rights reserved. Permission to use, copy, modify, and distribute this software and its documentation * for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all * copies and that both the copyright notice and this permission notice appear in supporting documentation. * The RINA laboratory of the Computer Science Department at Boston University makes no * representations about the suitability of this software for any purpose. */ /** * Flow Allocator Implementaion * Each IPC has a Flow Allocator to serve the application on top of it * @author Yuefeng Wang. Computer Science Department, Boston University * @version 1.0 * */ package rina.flowAllocator.impl; import java.util.LinkedHashMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import rina.flowAllocator.api.FlowAllocator; import rina.irm.impl.IRMImpl; import rina.message.DTP; import rina.object.internal.DirectoryForwardingTable; import rina.object.internal.Flow; import rina.object.internal.ForwardingTable; import rina.object.internal.Neighbor; import rina.object.internal.Neighbors; import rina.rib.impl.RIBImpl; import rina.util.MessageQueue; public class FlowAllocatorImpl implements FlowAllocator{ private Log log = LogFactory.getLog(this.getClass()); private RIBImpl rib = null; private IRMImpl irm = null; private int portIDRange = 10000; private LinkedHashMap<Integer,FlowAllocatorInstanceImpl> portIDToFAI = null; private LinkedHashMap<Integer, Flow> portIDToFlow = null; private LinkedHashMap<Integer, MessageQueue> flowQueues = null; private String IPCName = null; private String IPCInstance = null; private int rinaAddr = -1; private Neighbors neighbors = null; private DirectoryForwardingTable directoryForwardingTable = null; private ForwardingTable forwardingTable = null; //note: portID is used as a flowID for in the flow allocator public FlowAllocatorImpl(RIBImpl rib, IRMImpl irm) { this.rib = rib; this.irm = irm; this.portIDToFAI = new LinkedHashMap<Integer,FlowAllocatorInstanceImpl>(); this.portIDToFlow = new LinkedHashMap<Integer, Flow>(); this.flowQueues = new LinkedHashMap<Integer, MessageQueue>(); this.rib.addAttribute("portIDToFAI", this.portIDToFAI); this.rib.addAttribute("portIDToFlow", this.portIDToFlow); this.rib.addAttribute("flowQueues", this.flowQueues); this.IPCName = (String) this.rib.getAttribute("ipcName"); this.IPCInstance = (String)this.rib.getAttribute("ipcInstance"); this.neighbors = (Neighbors)this.rib.getAttribute("neighbors"); this.directoryForwardingTable = (DirectoryForwardingTable) this.rib.getAttribute("directoryForwardingTable"); this.forwardingTable = (ForwardingTable)this.rib.getAttribute("forwardingTable"); } public int submitAllocationRequest(Flow flowRequest) { this.log.debug("submitAllocationRequest is called"); this.rinaAddr = Integer.parseInt(this.rib.getAttribute("rinaAddr").toString()); int portID = -1; if(this.checkFlowRequest(flowRequest) == false) { this.log.error("Flow request is not well formed"); return -1; } portID = this.generatePortID(); flowRequest.setSrcAddr(this.rinaAddr); flowRequest.setSrcPortID(portID); this.flowQueues.put(portID, new MessageQueue()); // this one is used to get response from the FAI // Use the MeeeageQueue is just a temp way,//TODO MessageQueue notify = new MessageQueue(); FlowAllocatorInstanceImpl fai = new FlowAllocatorInstanceImpl(this.rib, this.irm, notify); fai.submitAllocationRequest(flowRequest); boolean result = Boolean.parseBoolean( new String( notify.getReceive()) ); if(result == false) { this.log.info("Flow allocation failed"); fai.stopFAI(); this.portIDToFAI.remove(portID); return -1; } this.portIDToFAI.put(portID, fai); this.portIDToFlow.put(portID, flowRequest); //update this flowQueue which is also accessible by the Data Transfer AE to do the RMT this.flowQueues.put(portID,new MessageQueue()); this.log.info("Flow allocation successful"); return portID; } public int receiveAllocationRequest(Flow flowRequest) { this.log.debug("receiveAllocationRequest is called"); this.rinaAddr = Integer.parseInt(this.rib.getAttribute("rinaAddr").toString()); int portID = -1; if(this.checkFlowRequestReceived(flowRequest) == false) { this.log.error("Dest application cannot be reached through this ipc"); return -1; }else { this.log.debug("Dest application found on this IPC"); } portID = this.generatePortID(); flowRequest.setSrcAddr(this.rinaAddr); flowRequest.setSrcPortID(portID); this.flowQueues.put(portID, new MessageQueue()); // this one is used to get response from the FAI // Use the MessageQueue is just a temp way,//TODO MessageQueue notify = new MessageQueue(); // needs to modify this FlowAllocatorInstanceImpl fai = new FlowAllocatorInstanceImpl(this.rib, this.irm, notify); fai.receiveAllocationRequest(flowRequest); boolean result = Boolean.parseBoolean( new String( notify.getReceive()) ); if(result == false) { this.log.info("Flow allocation failed"); fai.stopFAI(); this.portIDToFAI.remove(portID); return -1; } this.portIDToFAI.put(portID, fai); this.portIDToFlow.put(portID, flowRequest); //update this flowQueue which is also accessible by the Data Transfer AE to do the RMT this.flowQueues.put(portID,new MessageQueue()); this.log.info("Flow allocation successful"); return portID; } public void deallocateFlow(int portID) { this.flowQueues.remove(portID); this.portIDToFAI.get(portID).stopFAI(); this.portIDToFAI.remove(portID); } /** * Check if the IPC has the application requested on top of it * Now always return true * @param flowRequest * @return */ private boolean checkFlowRequestReceived(Flow flowRequest) { //check if this IPC has the target application on top of it return this.directoryForwardingTable.checkAppReachability(flowRequest.getSrcApInfo()); } /** * Check if the flow request is well-formed * Now return True all the time * @param flowRequest * @return */ private boolean checkFlowRequest(Flow flowRequest) { boolean result = true; // applicationProcessNamingInfo_t src = flowRequest.getSourceNamingInfo(); // applicationProcessNamingInfo_t dst = flowRequest.getDestinationNamingInfo(); // // String dstApName = dst.getApplicationProcessName(); // String dstApInstance = dst.getApplicationProcessInstance(); // String dstAeName = dst.getApplicationEntityName(); // String dstAeInstance = dst.getApplicationEntityInstance(); // // String srcApName = src.getApplicationProcessName(); // String srcApInstance = src.getApplicationProcessInstance(); // String srcAeName = src.getApplicationEntityName(); // String srcAeInstance = src.getApplicationEntityInstance(); // // // this.log.debug("DEST info: " + dstApName + "/" + dstApInstance + "/" + dstAeName + "/" + dstAeInstance); // this.log.debug("SRC info: " + srcApName + "/" + srcApInstance + "/" + srcAeName + "/" + srcAeInstance); return result; } private synchronized int generatePortID() { int portID = -1; portID = (int)( Math.random()* this.portIDRange); while(this.portIDToFAI.containsKey(portID)) { portID = (int)( Math.random()* this.portIDRange); } //this is to make it consistent this.portIDToFAI.put(portID, null); this.log.debug("portID generated is " + portID); return portID; } public void send(int flowID, byte[] msg) throws Exception { Flow flow = this.portIDToFlow.get(flowID); int handleID = flow.getDataTransferHandleID(); //if(handleID == -1) //{ //////////////////////////////////////////////////// //make sure there is a handle between Data Transfer AEs long nextHop = this.forwardingTable.getNextHop((int)flow.getDstAddr()); this.log.debug("FA (send) nnnnnnnnnnnnnnnnnnnnnnext hop of " + flow.getDstAddr() + " is " + nextHop); Neighbor neighbor = this.neighbors.getBeighbor(nextHop); handleID = this.irm.allocateFlow(this.IPCName, this.IPCInstance, "Data Transfer", "1", neighbor.getApName(), neighbor.getApInstance(), "Data Transfer", "1"); this.log.debug(this.IPCName + "/" + this.IPCInstance + "/" + neighbor.getApName() + "/" + neighbor.getApInstance()); //here both sender and receiver only use one handle to each other's Data Transfer AE flow.setDataTransferHandleID(handleID); this.log.debug(" this.portIDToFlow.get(flowID).getDataTransferHandleID()" + this.portIDToFlow.get(flowID).getDataTransferHandleID()); this.log.debug("HandleID between Data Transfer AEs is " + handleID ); // } DTP dtp = new DTP((short)flow.getDstAddr(), (short)flow.getSrcAddr(), (short)flow.getDstPortID(),(short)flow.getSrcPortID(), msg); dtp.printDTPHeader(); this.irm.send(handleID, dtp.toBytes()); } public byte[] receive(int flowID) { return this.flowQueues.get(flowID).getReceive(); } public synchronized IRMImpl getIrm() { return irm; } public synchronized Neighbors getNeighbors() { return neighbors; } }