package rina.ipc.impl;
/**
* @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.
*
* @author Yuefeng Wang. Computer Science Department, Boston University
*/
import java.util.LinkedList;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import rina.config.RINAConfig;
import rina.flowAllocator.impl.FlowAllocatorImpl;
import rina.ipc.ae.DataTransferAE;
import rina.ipc.ae.ManagementAE;
import rina.ipc.api.IPC;
import rina.irm.impl.IRMImpl;
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.DirectoryForwardingTable;
import rina.object.internal.Flow;
import rina.object.internal.ForwardingTable;
import rina.object.internal.IDDRecord;
import rina.object.internal.Neighbors;
import rina.rib.impl.RIBImpl;
import rina.ribDaemon.impl.RIBDaemonImpl;
import rina.util.FlowInfoQueue;
public class IPCImpl extends Thread implements IPC {
private Log log = LogFactory.getLog(this.getClass());
private RINAConfig config = null;
private RIBImpl rib = null;
private RIBDaemonImpl ribDaemon = null;
private IRMImpl irm = null;
private DataTransferAE dae = null;
private ManagementAE mae = null;
private FlowAllocatorImpl flowAllocator = null;
private String IPCName = null;
private String IPCInstance = null;
private String DIFName = null;
private int IPCLevel = -1;
//IPC process can be considered as an application
//apInfo is used when the IPC is using other IPC processes as underlying IPC process
//when this IPC can be seen as an application
private ApplicationProcessNamingInfo apInfo = null;
//this is the place where underlying IPCs give feed back to application, mainly incoming flow creation
// all underlying IPCs can access this message queue
private FlowInfoQueue flowInfoQueue = null;
private boolean listen = true;
/**
* It contains all the underlying DIFs of this IPC,and this info will be used when joining the DIF,
* The enroller will based on this information to tell who is direct neighbor
*/
private LinkedList<String> underlyingDIFs = null;
private boolean enrolled = false;
private DirectoryForwardingTable directoryForwardingTable= null;
private Neighbors neighbors = null;
private ForwardingTable forwardingTable = null;
private String routingProtocol = null;
private String linkCostPolicy = null;
//policy to generate address for new members
private String addressPolicy = null;
public IPCImpl(String configurationFile)
{
this.config = new RINAConfig(configurationFile);
this.rib = new RIBImpl();
this.rib.addAttribute("config", config);
this.IPCName = this.config.getIPCName();
this.DIFName = this.config.getDIFName();
this.IPCInstance = this.config.getIPCInstance();
this.IPCLevel = Integer.parseInt(this.config.getIPCLevel().trim());
this.apInfo = new ApplicationProcessNamingInfo( this.IPCName, this.IPCInstance);
this.rib.addAttribute("apInfo", this.apInfo);
this.flowInfoQueue = new FlowInfoQueue();
this.rib.addAttribute("flowInfoQueue", this.flowInfoQueue);
this.enrolled = this.config.getEnrolledState();
this.underlyingDIFs = this.config.getUnderlyingDIFs();
this.routingProtocol = this.config.getRoutingProtocol();
this.rib.addAttribute("routingProtocol", this.routingProtocol);
this.linkCostPolicy = this.config.getLinkCostPolity();
this.rib.addAttribute("linkCostPolicy", this.linkCostPolicy);
this.addressPolicy = this.config.getAddressPolicy();
this.rib.addAttribute("addressPolicy", this.addressPolicy);
if(this.enrolled == false)
{
//put the following info got from configuration file into the RIB, so ManagementAE could use to enroll
//but sometime, the following info may not exist in the configuration file
//in the latter case, it has to get such info from outside (maybe IDD)
this.rib.addAttribute("authenticatorApName", this.config.getAuthenticatorApName() );
this.rib.addAttribute("authenticatorApInstance", this.config.getAuthenticatorApInstance());
this.rib.addAttribute("authenPolicy", this.config.getAuthenPolicy());
this.rib.addAttribute("userName", this.config.getUserName());
this.rib.addAttribute("passWord", this.config.getPassWord());
}else // this is an authenticator
{
this.rib.addAttribute("rinaAddr", this.config.getRINAAddr());
}
this.rib.addAttribute("difName", this.DIFName);
this.rib.addAttribute("ipcName", this.IPCName);
this.rib.addAttribute("ipcInstance", this.IPCInstance);
this.rib.addAttribute("ipcLevel", this.IPCLevel);
this.rib.addAttribute("enrolledState", this.enrolled);
this.rib.addAttribute("underlyingDIFs", this.underlyingDIFs);
this.directoryForwardingTable = new DirectoryForwardingTable();
this.neighbors = new Neighbors();
this.rib.addAttribute("directoryForwardingTable", this.directoryForwardingTable);
this.rib.addAttribute("neighbors", this.neighbors);
this.forwardingTable = new ForwardingTable(this.neighbors);
this.rib.addAttribute("forwardingTable", this.forwardingTable);
this.irm = new IRMImpl(this.rib);
this.flowAllocator = new FlowAllocatorImpl(this.rib, this.irm);
//put this pointer to the RIB, it might be used to deal with flow allocation
this.rib.addAttribute("flowAllocator", this.flowAllocator);
this.ribDaemon = new RIBDaemonImpl(this.rib, this.irm);
this.rib.addAttribute("ribDaemon", this.ribDaemon);
this.dae = new DataTransferAE(this.IPCName, this.IPCInstance, "1", this.rib, this.irm);
this.mae = new ManagementAE(this.IPCName, this.IPCInstance, "1", this.rib, this.irm);
//if this IPC is a authenticator then register itself to IDD, such that new member could find it and join
//the DIF through it.
if(this.enrolled == true)
{
this.registerDIFToIDD();
}
}
/**
* construct an IPC process, and pass it with a list of underlying IPC processes
* @param config
* @param underlyigIPCList
*/
public IPCImpl(RINAConfig config, LinkedList<IPCImpl> underlyigIPCList)
{
this.config = config;
this.rib = new RIBImpl();
this.rib.addAttribute("config", config);
this.IPCName = this.config.getIPCName();
this.DIFName = this.config.getDIFName();
this.IPCInstance = this.config.getIPCInstance();
this.IPCLevel = Integer.parseInt(this.config.getIPCLevel().trim());
this.apInfo = new ApplicationProcessNamingInfo( this.IPCName, this.IPCInstance);
this.rib.addAttribute("apInfo", this.apInfo);
this.flowInfoQueue = new FlowInfoQueue();
this.rib.addAttribute("flowInfoQueue", this.flowInfoQueue);
this.enrolled = this.config.getEnrolledState();
this.underlyingDIFs = this.config.getUnderlyingDIFs();
this.routingProtocol = this.config.getRoutingProtocol();
this.rib.addAttribute("routingProtocol", this.routingProtocol);
this.linkCostPolicy = this.config.getLinkCostPolity();
this.rib.addAttribute("linkCostPolicy", this.linkCostPolicy);
this.addressPolicy = this.config.getAddressPolicy();
this.rib.addAttribute("addressPolicy", this.addressPolicy);
if(this.enrolled == false)
{
//put the following info got from configuration file into the RIB, so ManagementAE could use to enroll
//but sometime, the following info may not exist in the configuration file
//in the latter case, it has to get such info from outside (maybe IDD)
this.rib.addAttribute("authenticatorApName", this.config.getAuthenticatorApName() );
this.rib.addAttribute("authenticatorApInstance", this.config.getAuthenticatorApInstance());
this.rib.addAttribute("authenPolicy", this.config.getAuthenPolicy());
this.rib.addAttribute("userName", this.config.getUserName());
this.rib.addAttribute("passWord", this.config.getPassWord());
}else // this is an authenticator
{
this.rib.addAttribute("rinaAddr", this.config.getRINAAddr());
}
this.rib.addAttribute("difName", this.DIFName);
this.rib.addAttribute("ipcName", this.IPCName);
this.rib.addAttribute("ipcInstance", this.IPCInstance);
this.rib.addAttribute("ipcLevel", this.IPCLevel);
this.rib.addAttribute("enrolledState", this.enrolled);
this.rib.addAttribute("underlyingDIFs", this.underlyingDIFs);
this.directoryForwardingTable = new DirectoryForwardingTable();
this.neighbors = new Neighbors();
this.rib.addAttribute("directoryForwardingTable", this.directoryForwardingTable);
this.rib.addAttribute("neighbors", this.neighbors);
this.forwardingTable = new ForwardingTable(this.neighbors);
this.rib.addAttribute("forwardingTable", this.forwardingTable);
this.irm = new IRMImpl(this.rib);
this.flowAllocator = new FlowAllocatorImpl(this.rib, this.irm);
//put this pointer to the RIB, it might be used to deal with flow allocation
this.rib.addAttribute("flowAllocator", this.flowAllocator);
this.ribDaemon = new RIBDaemonImpl(this.rib, this.irm);
this.rib.addAttribute("ribDaemon", this.ribDaemon);
// add to its underlying IPCs
for(int i = 0; i< underlyigIPCList.size(); i++)
{
this.addIPC(underlyigIPCList.get(i));
}
this.dae = new DataTransferAE(this.IPCName, this.IPCInstance, "1", this.rib, this.irm);
this.mae = new ManagementAE(this.IPCName, this.IPCInstance, "1", this.rib, this.irm);
//if this IPC is a authenticator then register itself to IDD, such that new member could find it and join
//the DIF through it.
if(this.enrolled == true)
{
this.registerDIFToIDD();
}
}
public void run()
{
this.log.debug("IPC process started");
while(this.listen)
{
Flow flow = this.flowInfoQueue.getFlowInfo();
//create a handle for the incoming flow request
int handleID = this.irm.addIncomingHandle(flow);
}
}
// The following four are related to flow Allocator
// TODO
public int allocateFlow(Flow flow) {
return this.flowAllocator.submitAllocationRequest(flow);
}
public void deallocateFlow(int portID) {
this.flowAllocator.deallocateFlow(portID);
}
public void send(int flowID, byte[] msg) throws Exception {
this.flowAllocator.send(flowID,msg);
}
public byte[] receive(int flowID) {
return this.flowAllocator.receive(flowID);
}
/**
* This checks if this ipc can reach the remote application with name apName
* @param apName
* @return
*/
public synchronized boolean checkRemoteApp(String apName) {
return this.directoryForwardingTable.checkAppReachability(apName);
}
/**
* This checks if this ipc can reach the remote application with apInfo
* @param apName
* @return
*/
public synchronized boolean checkRemoteApp(ApplicationProcessNamingInfo apInfo) {
return this.directoryForwardingTable.checkAppReachability(apInfo);
}
public synchronized FlowAllocatorImpl getFlowAllocator() {
return flowAllocator;
}
public synchronized RIBImpl getRib() {
return rib;
}
public synchronized IRMImpl getIrm() {
return irm;
}
// this ipc first stores this in its RIB forwardingDirectory,
// then send to all its neighbors
public void registerApplication(ApplicationProcessNamingInfo apInfo, FlowInfoQueue flowInfoQueue) {
//System.out.println("ccccccccccccccccc" + apInfo.getPrint() );
this.mae.registerApplication( apInfo, flowInfoQueue);
}
public void deregisterApplication(ApplicationProcessNamingInfo apInfo) {
//TODO
this.log.info("deregisterApplication method is called. apinfo is " + apInfo.getPrint());
}
public IDDRecord queryIDD(String DIFName)
{
return this.mae.queryIDD(DIFName);
}
public IDDRecord queryIDD(ApplicationProcessNamingInfo apInfo)
{
return this.mae.queryIDD(apInfo);
}
public IDDRecord queryIDD(iddMessage_t iddRequestMsg)
{
return this.irm.queryIDD(iddRequestMsg);
}
/**
* Register itself as the DIF authenticator
*/
public void registerDIFToIDD()
{
iddMessage_t.Builder iddRegMsg = iddMessage_t.newBuilder();
iddRegMsg.setOpCode(opCode_t.Register);
iddRegMsg.setDifName(this.DIFName);
ApplicationProcessNamingInfo authenticatorInfo
= new ApplicationProcessNamingInfo(this.IPCName, this.IPCInstance);
iddRegMsg.addAuthenticatorNameInfo(authenticatorInfo.convert());
iddRegMsg.setTimeStamp(System.currentTimeMillis());
this.registerToIDD(iddRegMsg.buildPartial());
}
public void registerAppToIDD(ApplicationProcessNamingInfo apInfo)
{
iddMessage_t.Builder iddRegMsg = iddMessage_t.newBuilder();
iddRegMsg.setOpCode(opCode_t.Register);
iddRegMsg.setApplicationNameInfo(apInfo.convert());
iddResponse_t.Builder appRecord = iddResponse_t.newBuilder();
appRecord.setDifName(this.DIFName);
ApplicationProcessNamingInfo ipcProcessInfo
= new ApplicationProcessNamingInfo(this.IPCName, this.IPCInstance);
appRecord.setIpcProcessNameInfo(ipcProcessInfo.convert());
//add supporing DIFs of this IPC process
for(int i = 0; i < this.underlyingDIFs.size(); i++)
{
appRecord.addSupportingDIFNames(this.underlyingDIFs.get(i));
}
iddRegMsg.addIddResponse(appRecord.buildPartial());
iddRegMsg.setTimeStamp(System.currentTimeMillis());
this.registerToIDD(iddRegMsg.buildPartial());
}
public void registerToIDD(iddMessage_t iddRegMsg)
{
this.mae.registerToIDD(iddRegMsg);
}
public void addIPC(IPCImpl ipc) {
this.irm.addIPC(ipc);
}
public synchronized String getIPCName() {
return IPCName;
}
public synchronized void setIPCName(String iPCName) {
IPCName = iPCName;
}
public synchronized String getIPCInstance() {
return IPCInstance;
}
public synchronized void setIPCInstance(String iPCInstance) {
IPCInstance = iPCInstance;
}
public synchronized String getDIFName() {
return DIFName;
}
public synchronized void setDIFName(String dIFName) {
DIFName = dIFName;
}
public synchronized DirectoryForwardingTable getDirectoryForwardingTable() {
return directoryForwardingTable;
}
public synchronized void setDirectoryForwardingTable(
DirectoryForwardingTable directoryForwardingTable) {
this.directoryForwardingTable = directoryForwardingTable;
}
}