/** * @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. */ package application.component.impl; import java.util.LinkedHashMap; import java.util.LinkedList; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import rina.config.RINAConfig; import rina.ipc.impl.IPCImpl; import rina.irm.util.HandleEntry; import rina.irm.util.UnderlyingDIFsInfo; import rina.message.CDAP; import rina.object.gpb.IDDMessage_t.iddMessage_t; import rina.object.gpb.IDDMessage_t.iddResponse_t; import rina.object.gpb.IDDMessage_t.opCode_t; import rina.object.internal.ApplicationProcessNamingInfo; import rina.object.internal.Flow; import rina.object.internal.IDDRecord; import rina.rib.impl.RIBImpl; import rina.util.FlowInfoQueue; import application.ae.DAPManagementAE; import application.component.api.IPCResourceManager; import com.google.protobuf.InvalidProtocolBufferException; /** * This is a component of an application process, which manages of all underlying IPC process * Note: In an IPC process, there is a component called IRM (IPC Resource Manager). IPC manager here is the same * with non-DIF0 IPC process's IRM. * * @author Yuefeng Wang. Computer Science Department, Boston University * */ public class IPCResourceManagerImpl implements IPCResourceManager { private Log log = LogFactory.getLog(this.getClass()); private RIBImpl rib = null; private UnderlyingDIFsInfo underlyingDIFsInfo = null; private ApplicationProcessNamingInfo apInfo = null; //private boolean listen = true; //this is to used get flow allocation info from underlying ipc private FlowInfoQueue flowInfoQueue = null; private LinkedHashMap<Integer, HandleEntry > handleMap = null; //this one is used just for searching purpose private LinkedHashMap<String, HandleEntry> existingHandle = null; private int handleIDRange = 10000; private DAPManagementAE mae = null; public IPCResourceManagerImpl(RIBImpl rib) { this.rib = rib; this.underlyingDIFsInfo = new UnderlyingDIFsInfo(this.rib); this.apInfo = (ApplicationProcessNamingInfo)this.rib.getAttribute("apInfo"); this.flowInfoQueue = (FlowInfoQueue)this.rib.getAttribute("flowInfoQueue"); this.handleMap = new LinkedHashMap<Integer, HandleEntry >(); this.rib.addAttribute("handleMap", this.handleMap); this.existingHandle = new LinkedHashMap<String, HandleEntry>(); } // public void run() // { // while(this.listen) // { // Flow flow = this.flowInfoQueue.getFlowInfo(); // // //create a handle for the incoming flow request // // this.addIncomingHandle(flow); // // } // } public int addIncomingHandle(Flow flow) { int handleID = this.generateHandleID(); HandleEntry he = new HandleEntry(flow.getSrcApInfo().getApName(), flow.getSrcApInfo().getApInstance(), flow.getSrcApInfo().getAeName(),flow.getSrcApInfo().getAeInstance(), flow.getDstApInfo().getApName(), flow.getDstApInfo().getApInstance(), flow.getDstApInfo().getAeName(), flow.getDstApInfo().getAeInstance(), flow.getUnderlyingIPCName(), flow.getUnderlyingIPCInstance(), handleID); he.setSrcPortID((int)flow.getSrcPortID()); he.setDstPortID((int)flow.getDstPortID()); String key = flow.getDstApInfo().getApName() + flow.getDstApInfo().getApInstance(); this.handleMap.put(handleID, he); this.existingHandle.put(key, he); this.log.debug("New Incoming handle added, and flow info:" + flow.getPrint()); return handleID; } public synchronized void addIPC(IPCImpl ipc) { this.underlyingDIFsInfo.addIPC(ipc); } public synchronized void removeIPC(String IPCName, String IPCInstance) { this.underlyingDIFsInfo.removeIPC(IPCName, IPCInstance); //check all existing flows, if it is using this IPC process, remove that handle int totalHandleNumber = this.handleMap.size(); Object[] keyArray = this.handleMap.keySet().toArray(); for(int i = 0; i < totalHandleNumber; i++) { int handleID = Integer.parseInt(keyArray[i].toString()); HandleEntry he = this.handleMap.get(handleID); he.print(); if(he.getUnderlyingIPCName().equals(IPCName) && he.getUnderlyingIPCInstance().equals(IPCInstance)) { this.deallocate(handleID); } } this.log.debug("IPC " + IPCName + "/" + IPCInstance + " removed "); } public synchronized LinkedList<String> getUnderlyingDIFs() { return this.underlyingDIFsInfo.getUnderlyingDIFs(); } public synchronized LinkedList<IPCImpl> getUnderlyingIPCs() { return this.underlyingDIFsInfo.getUnderlyingIPCList(); } /** * Return the handle */ public int allocateFlow(String srcApName, String dstApName) { return this.allocateFlow(srcApName, "", dstApName, ""); } // The following is a back up of previous method // /** // * Return the handle // */ // public int allocateFlow(String srcApName, String dstApName) { // // // // // //for now we assume only one flow between two application // // String key = srcApName + dstApName; // // //this.log.debug("irm handle key is " + key); // // if(this.existingHandle.containsKey(key)) // { // //this.log.debug("the request to dest has a handle before, we will use the existing one"); // return this.existingHandle.get(key).getHandleID(); // } // //////////////////////////////////////////////////////////////////// // // // IPCImpl ipc = this.getUnderlyingIPC(dstApName); // // //no ipc can reach the remote dst application // if(ipc == null) // { // // //Dynamic DIF formation // int success = this.dynamicDIFFormation(srcApName, dstApName); // // if(success == -1) // { // this.log.debug("DDF failed, return -1 as the handle"); // return -1; // }else if(success == 0) // { // //called the allocate flow method again, as there is new IPC could relay now // this.log.debug("DDF successful"); // // // //TESTNOW // return 999; // //return this.allocateFlow(srcApName,dstApName); // } // // } // // String ipcName = ipc.getIPCName(); // String ipcInstance = ipc.getIPCInstance(); // // // int handleID = this.generateHandleID(); // // HandleEntry he = new HandleEntry(srcApName, dstApName, ipcName, ipcInstance, handleID); // // // // this.handleMap.put(handleID, he); // this.existingHandle.put(key, he); // // // Flow flow = new Flow(srcApName, dstApName); // // ipc.allocateFlow(flow); // // flow.print(); // // he.setSrcPortID((int)flow.getSrcPortID()); // he.setDstPortID((int)flow.getDstPortID()); // // // he.print(); // // // return handleID; // // } /** * This is to dynamically create a DIF, and this is called when an application wants to allocate a flow to another application * but there is no existing underlying DIF could help to reach the destination application. * At this time, an new DIF needs to be created to provide the transportation service, however there should be an application pre-registered to provide the relay services. * @param srcApName * @param dstApName */ private synchronized int dynamicDIFFormation(String srcApName, String srcApInstance, String dstApName, String dstApInstance) { this.log.debug("Dynamic DIF Formation is called, [srcApName/srcApInstance/dstApName/dstApInstance]: " + srcApName + "/" + srcApInstance + "/" + dstApName + "/" + dstApInstance); int success = -1; //application name is in the formation: relay + dstApName + dstApInstance //for example for "app""1", the relay application has a name "relay:app1" IDDRecord iddRecord = this.queryServiceToIDD("relay:" + dstApName + dstApInstance); if(iddRecord == null) { return success; }else { this.log.debug("relay service found"); iddRecord.print(); success = 0; } //send request to the app provides relay service, and fork ipc process to joins the DIF //Remember we use IPCProcessInfo to carry the app info providing the relay service ApplicationProcessNamingInfo relayApp = iddRecord.getAppRecordList().get(0).getIpcProcessInfo(); String relayApName = relayApp.getApName(); String relayApInstance = relayApp.getApInstance(); this.log.debug("App that provides relay services to [apName/ApInstance:" + dstApName + "/" + dstApInstance + "]is " + relayApName + "/" + relayApInstance); //To Relay application //Note: not to the Management AE of relay application, the handle just to relay application int handleToRelayAp = this.allocateFlow(srcApName,srcApInstance, "Management", "1", relayApName, relayApInstance, "", ""); this.log.debug("handle to relay app: " + relayApName + "/" + relayApInstance + " is " + handleToRelayAp); //send a CDAP message M_CREATE to relay app to form the DIF, and fork and IPC to joins the DIF CDAP.CDAPMessage M_CREATE = rina.message.CDAPMessageGenerator.generateM_CREATE ( "relay dif", "/daf/relay/dif/", 99 ); try { this.send(handleToRelayAp, M_CREATE.toByteArray()); this.log.debug("M_CREATE(relay dif) sent to relay ap"); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); success = -1; return success; } //wait for M_CREATE_R containing relay DIF info byte[] reply = this.receive(handleToRelayAp); String relayDIFName = null; try { CDAP.CDAPMessage M_CREATE_R = CDAP.CDAPMessage.parseFrom(reply); this.log.debug("M_CREATE_R (relay dif) received"); if(M_CREATE_R.getResult() == 0) { relayDIFName = M_CREATE_R.getObjValue().getStrval(); this.log.debug("Relay DIF found, and DIF name is " + relayDIFName); }else { this.log.error("Relay DIF not found"); success = -1; return success; } } catch (InvalidProtocolBufferException e) { // TODO Auto-generated catch block e.printStackTrace(); success = -1; return success; } //fork an IPC process to join that DIF //config the IPC process RINAConfig ipcConfig = new RINAConfig(); //ipcConfig.setProperty("rina.ipc.flag", "1"); //non-DIF zero ipc //NOTE: Here we set the level to be 1 FIXME ipcConfig.setProperty("rina.ipc.level", "1"); ipcConfig.setProperty("rina.ipc.name", "forked:ipc:" + this.apInfo.getApName() + ":" + this.apInfo.getApInstance()); ipcConfig.setProperty("rina.ipc.instance", "1"); //This IPC will join that DIF ipcConfig.setProperty("rina.dif.enrolled", "false"); ipcConfig.setProperty("rina.dif.name", relayDIFName); ipcConfig.setProperty("rina.ipc.userName", "BU"); ipcConfig.setProperty("rina.ipc.passWord", "BU"); ipcConfig.setProperty("rina.enrollment.authenPolicy", "AUTH_PASSWD"); ipcConfig.setProperty("rina.routing.protocol","linkState"); ipcConfig.setProperty("rina.routingEntrySubUpdatePeriod","2"); ipcConfig.setProperty("rina.checkNeighborPeriod","2"); ipcConfig.setProperty("rina.linkCost.policy","hop"); ipcConfig.setUnderlyingDIFs(this.getUnderlyingDIFs()); LinkedList<IPCImpl> underlyigIPCList = this.getUnderlyingIPCs(); IPCImpl newIPC = new IPCImpl(ipcConfig, underlyigIPCList); newIPC.start(); this.log.debug("new IPC process is forked on request."); //add the new ipc to the app as its underlying IPC this.addIPC(newIPC); return success; } //query IDD for the relay service private IDDRecord queryServiceToIDD(String serviceName) { IDDRecord iddRecord = null; IPCImpl ipc = this.getAnyUnderlyingIPCToIDD(); //NOTE: for relay service. apName is "relay", apInstance is dest app.apName + dest app.spInstance iddRecord = ipc.queryIDD(new ApplicationProcessNamingInfo(serviceName)) ; return iddRecord; } public void registerServiceToIDD(String serviceName) { IPCImpl ipc = this.getAnyUnderlyingIPCToIDD(); iddMessage_t.Builder iddRegMsg = iddMessage_t.newBuilder(); iddRegMsg.setOpCode(opCode_t.Register); //here app name querryed is service name iddRegMsg.setApplicationNameInfo(new ApplicationProcessNamingInfo(serviceName).convert()); iddResponse_t.Builder appRecord = iddResponse_t.newBuilder(); //here we use ipcProcessInfo to carry the app info which provides the service appRecord.setIpcProcessNameInfo(this.apInfo.convert()); iddRegMsg.addIddResponse(appRecord.buildPartial()); iddRegMsg.setTimeStamp(System.currentTimeMillis()); ipc.registerToIDD(iddRegMsg.buildPartial()); } /** * It will use any one of the underlying IPC to talk to IDD * @return */ private synchronized IPCImpl getAnyUnderlyingIPCToIDD() { return this.underlyingDIFsInfo.getAnyUnderlyingIPC(); } public int allocateFlow(String srcApName, String srcApInstance, String dstApName, String dstApInstance) { return this.allocateFlow(srcApName, srcApInstance, "", "", dstApName, dstApInstance, "", ""); } /** * old method, just for record now. */ // public int allocateFlow(String srcApName, String srcApInstance, String dstApName, String dstApInstance) { // // // //for now we assume only one flow between two application // // String key = srcApName + srcApInstance + dstApName + dstApInstance; // // //this.log.debug("irm handle key is " + key); // // if(this.existingHandle.containsKey(key)) // { // // this.log.debug("the request to dest has a handle before, we will use the existing one"); // return this.existingHandle.get(key).getHandleID(); // } // //////////////////////////////////////////////////////////////////// // // // IPCImpl ipc = this.getUnderlyingIPC(dstApName, dstApInstance); // // //no ipc can reach the remote dst application // if(ipc == null) // { // //Dynamic DIF formation // int success = this.dynamicDIFFormation(srcApName, dstApName); // // if(success == -1) // { // this.log.debug("DDF failed, return -1 as the handle"); // return -1; // }else if(success == 0) // { // //called the allocate flow method again, as there is new IPC could relay now // this.log.debug("DDF successful, and call the allocateFlow again."); // // try { // int sleepTime = 5; // this.log.debug("Sleep for " + sleepTime + " seconds such that the routing in the new DIF converge for the first time"); // Thread.sleep(1000*5); // // } catch (InterruptedException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } // // return this.allocateFlow(srcApName,dstApName); // } // } // // String ipcName = ipc.getIPCName(); // String ipcInstance = ipc.getIPCInstance(); // // // int handleID = this.generateHandleID(); // // HandleEntry he = new HandleEntry(srcApName,srcApInstance, dstApName,dstApInstance, ipcName, ipcInstance, handleID); // // this.handleMap.put(handleID, he); // this.existingHandle.put(key, he); // // // Flow flow = new Flow(srcApName,srcApInstance, "", "", dstApName, dstApInstance,"", ""); // // ipc.allocateFlow(flow); // // flow.print(); // // he.setSrcPortID((int)flow.getSrcPortID()); // he.setDstPortID((int)flow.getDstPortID()); // // // he.print(); // // // return handleID; // // } /** * This returns the IPC which can reach the application * @param dstApName * @return */ private synchronized IPCImpl getUnderlyingIPC(String dstApName, String dstApInstance) { return this.underlyingDIFsInfo.getUnderlyingIPCToApp(dstApName, dstApInstance); } public synchronized void deallocate(int handleID) { this.log.debug("dellocate is called to remove handle with ID " + handleID); HandleEntry he = this.handleMap.get(handleID); this.handleMap.remove(handleID); String key = he.getKey(); this.existingHandle.remove(key); this.log.debug("handle " + handleID + " removed"); } public void send(int handleID, byte[] msg) throws Exception { if(this.handleMap.containsKey(handleID)) { HandleEntry he = this.handleMap.get(handleID); String underlyingIPCName = he.getUnderlyingIPCName(); String underlyingIPCNameInstance = he.getUnderlyingIPCInstance(); int srcPortID = he.getSrcPortID(); this.log.debug("irm send on ipc " + underlyingIPCName + "/" + underlyingIPCNameInstance + ", portID: " + srcPortID); IPCImpl ipc = this.underlyingDIFsInfo.getUnderlyingIPC(underlyingIPCName, underlyingIPCNameInstance); ipc.send(srcPortID, msg); }else { this.log.error("handleID " + handleID + " does not exist "); throw new Exception("Handle does not exist"); } } public byte[] receive(int handleID) { byte[] msg = null; if(this.handleMap.containsKey(handleID)) { HandleEntry he = this.handleMap.get(handleID); String underlyingIPCName = he.getUnderlyingIPCName(); String underlyingIPCInstance = he.getUnderlyingIPCInstance(); int srcPortID = he.getSrcPortID(); IPCImpl ipc = this.underlyingDIFsInfo.getUnderlyingIPC(underlyingIPCName, underlyingIPCInstance); he.print(); if(ipc !=null) { msg = ipc.receive(srcPortID); }else { this.log.error("Underlying IPC not found"); } } return msg; } private synchronized int generateHandleID() { int handleID = -1; handleID = (int)( Math.random()* this.handleIDRange); while(this.handleMap.containsKey(handleID)) { handleID = (int)( Math.random()* this.handleIDRange); } this.log.debug("Handle generated is " + handleID); this.handleMap.put(handleID, null); return handleID; } public RIBImpl getRib() { return rib; } public void setRib(RIBImpl rib) { this.rib = rib; } public void setMae(DAPManagementAE mae) { this.mae = mae; } public synchronized int allocateFlow(String srcApName, String srcApInstance, String srcAeName, String srcAeInstance, String dstApName, String dstApInstance, String dstAeName, String dstAeInstance) { //assumme there are only one flow between two aes String key = srcApName + srcApInstance + srcAeName + srcAeInstance + dstApName + dstApInstance + dstAeName + dstAeInstance; this.log.debug("irm handle key is " + key); if(this.existingHandle.containsKey(key)) { // this.log.debug("the request to dest has a handle before, we will use the existing one"); return this.existingHandle.get(key).getHandleID(); } //////////////////////////////////////////////////////////////////// IPCImpl ipc = this.getUnderlyingIPC(dstApName, dstApInstance); //no ipc can reach the remote dst application if(ipc == null) { //Dynamic DIF formation int success = this.dynamicDIFFormation(srcApName,srcApInstance, dstApName, dstApInstance); if(success == -1) { this.log.debug("DDF failed, return -1 as the handle"); return -1; }else if(success == 0) { //called the allocate flow method again, as there is new IPC could relay now this.log.debug("DDF successful, and call the allocateFlow again."); try { int sleepTime = 5; this.log.debug("Sleep for " + sleepTime + " seconds such that the routing in the new DIF converge for the first time"); Thread.sleep(1000*5); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } return this.allocateFlow(srcApName,srcApInstance, dstApName, dstApInstance); } } String ipcName = ipc.getIPCName(); String ipcInstance = ipc.getIPCInstance(); int handleID = this.generateHandleID(); HandleEntry he = new HandleEntry(srcApName,srcApInstance, srcAeName, srcAeInstance, dstApName,dstApInstance, dstAeName, dstAeInstance, ipcName, ipcInstance, handleID); this.handleMap.put(handleID, he); this.existingHandle.put(key, he); Flow flow = new Flow(srcApName,srcApInstance, srcAeName, srcAeInstance, dstApName,dstApInstance, dstAeName, dstAeInstance); ipc.allocateFlow(flow); flow.print(); he.setSrcPortID((int)flow.getSrcPortID()); he.setDstPortID((int)flow.getDstPortID()); he.print(); return handleID; } public synchronized HandleEntry getHandleEntry (int handleID) { if(this.handleMap.containsKey(handleID)) { return this.handleMap.get(handleID); }else { return null; } } }