package es.tid.pce.computingEngine;
import java.io.DataOutputStream;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.LinkedList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import es.tid.of.DataPathID;
import es.tid.pce.pcep.constructs.ErrorConstruct;
import es.tid.pce.pcep.constructs.StateReport;
import es.tid.pce.pcep.messages.PCEPError;
import es.tid.pce.pcep.messages.PCEPReport;
import es.tid.pce.pcep.objects.PCEPErrorObject;
import es.tid.pce.pcep.PCEPProtocolViolationException;
import es.tid.pce.pcep.constructs.PCEPIntiatedLSP;
import es.tid.pce.pcep.constructs.Response;
import es.tid.pce.pcep.messages.PCEPInitiate;
import es.tid.pce.pcep.messages.PCEPMessageTypes;
import es.tid.pce.pcep.messages.PCEPResponse;
import es.tid.pce.pcep.objects.ExplicitRouteObject;
import es.tid.pce.pcep.objects.LSP;
import es.tid.pce.pcep.objects.SRP;
import es.tid.rsvp.objects.subobjects.DataPathIDEROSubobject;
import es.tid.rsvp.objects.subobjects.EROSubobject;
import es.tid.rsvp.objects.subobjects.UnnumberIfIDEROSubobject;
import es.tid.tedb.ReachabilityManager;
import es.tid.util.UtilsFunctions;
/**
* It's a copy of PCEPResponse. It's an interface and it can be encoded as a PCEPResponse
* or as a PCEPInitiate
*
*/
public class ComputingResponse
{
private byte messageBytes[];//The bytes of the message
private int encodingType = PCEPMessageTypes.MESSAGE_PCREP;
public LinkedList<Response> ResponseList;
private Logger log=LoggerFactory.getLogger("PCEP listener");
public LinkedList<StateReport> ReportList;
public LinkedList<StateReport> getReportList() {
return ReportList;
}
public void setReportList(LinkedList<StateReport> reportList) {
ReportList = reportList;
}
private ReachabilityManager reachabilityManager;
/**
* Construct new PCEP Request from scratch
*/
public ComputingResponse()
{
super();
ResponseList=new LinkedList<Response>();
ReportList = new LinkedList<StateReport>();
}
public void addResponse(Response response)
{
this.ResponseList.add(response);
}
public Response getResponse(int index)
{
return this.ResponseList.get(index);
}
public void addReport(StateReport report)
{
this.ReportList.add(report);
}
public StateReport getResport(int index)
{
return this.ReportList.get(index);
}
public LinkedList<Response> getResponseList()
{
return ResponseList;
}
public void setResponsetList(LinkedList<Response> responseList)
{
ResponseList = responseList;
}
/*
* Encodes the PCEP Response Message
*/
public void encode(boolean isFather) throws PCEPProtocolViolationException
{
switch (encodingType)
{
case PCEPMessageTypes.MESSAGE_PCREP:
PCEPResponse p_resp = new PCEPResponse();
p_resp.setResponsetList(ResponseList);
p_resp.encode();
setMessageBytes(p_resp.getBytes());
break;
case PCEPMessageTypes.MESSAGE_INITIATE:
if (isFather)
{
//This part will suppose the Initiate has only one Path
ExplicitRouteObject ero = ResponseList.get(0).getPath(0).geteRO();
EroAndIP EaIP;
//This is something that should be corrected in the future
//This class is to supposed to leave some bytes prepared for sending
//The bytes from n=1 will be left for the outer class to encode
//But the rest have to be encoded and sent from inside the class
//It's a structural problem. The calling class should be changed
int n = 2;
while ((EaIP = getNthSubERO(ero,n))!=null)
{
createInitAndSend(EaIP);
n++;
}
EaIP = getNthSubERO(ero,1);
PCEPInitiate pInit = new PCEPInitiate();
LinkedList<PCEPIntiatedLSP> pcepIntiatedLSPList = new LinkedList<PCEPIntiatedLSP>();
PCEPIntiatedLSP pILSP = new PCEPIntiatedLSP();
LSP lsp = new LSP();
SRP rsp = new SRP();
ExplicitRouteObject ero_lsp = EaIP.ero;
pILSP.setLsp(lsp);
pILSP.setRsp(rsp);
pILSP.setEro(ero_lsp);
pcepIntiatedLSPList.add(pILSP);
try
{
pInit.encode();
}
catch (Exception e)
{
log.info(UtilsFunctions.exceptionToString(e));
}
setMessageBytes(pInit.getBytes());
}
else
{
PCEPInitiate pInit = new PCEPInitiate();
LinkedList<PCEPIntiatedLSP> pcepIntiatedLSPList = new LinkedList<PCEPIntiatedLSP>();
for (int i = 0; i < ResponseList.size(); i++)
{
PCEPIntiatedLSP pILSP = new PCEPIntiatedLSP();
LSP lsp = new LSP();
SRP rsp = new SRP();
ExplicitRouteObject ero = ResponseList.get(i).getPath(0).geteRO();
pILSP.setLsp(lsp);
pILSP.setRsp(rsp);
pILSP.setEro(ero);
pcepIntiatedLSPList.add(pILSP);
}
pInit.setPcepIntiatedLSPList(pcepIntiatedLSPList);
pInit.encode();
log.info("Encoding Son Finished, pInit.getBytes(): " + pInit.getBytes());
setMessageBytes(pInit.getBytes());
}
break;
case PCEPMessageTypes.MESSAGE_REPORT:
if (ReportList.isEmpty()){
PCEPError perror = new PCEPError();
ErrorConstruct error = new ErrorConstruct();
PCEPErrorObject e = new PCEPErrorObject();
e.setErrorType(24);
e.setErrorValue(3);
error.getErrorObjList().add(e);
perror.setError(error);
}
else {
PCEPReport p_rep = new PCEPReport();
p_rep.setStateReportList(ReportList);
p_rep.encode();
setMessageBytes(p_rep.getBytes());
}
break;
}
}
private void createInitAndSend(EroAndIP EaIP)
{
PCEPInitiate pInit = new PCEPInitiate();
LinkedList<PCEPIntiatedLSP> pcepIntiatedLSPList = new LinkedList<PCEPIntiatedLSP>();
PCEPIntiatedLSP pILSP = new PCEPIntiatedLSP();
LSP lsp = new LSP();
SRP rsp = new SRP();
ExplicitRouteObject ero_lsp = EaIP.ero;
pILSP.setLsp(lsp);
pILSP.setRsp(rsp);
pILSP.setEro(ero_lsp);
pcepIntiatedLSPList.add(pILSP);
try
{
pInit.encode();
Socket clientSocket;
clientSocket = new Socket(EaIP.address, 2222);
DataOutputStream out_to_node = new DataOutputStream(clientSocket.getOutputStream());
out_to_node.write(pInit.getBytes());
out_to_node.flush();
}
catch (Exception e)
{
log.info(UtilsFunctions.exceptionToString(e));
}
}
private EroAndIP getNthSubERO(ExplicitRouteObject ero, int n)
{
// reachabilityManager should not be null if this is a fathers algorithm
// If it is, make sure the algorithms set the reachabilityManager
Inet4Address firstID = null;
for (int i = 0; i < ero.getEROSubobjectList().size(); i++)
{
if ((ero.getEROSubobjectList().get(i)) instanceof UnnumberIfIDEROSubobject)
{
UnnumberIfIDEROSubobject unAux = (UnnumberIfIDEROSubobject)ero.getEROSubobjectList().get(i);
firstID = reachabilityManager.getDomain(unAux.getRouterID());
break;
}
}
int offset = 0, i = 0;
Inet4Address currentID = firstID;
ExplicitRouteObject subERO = null;
EroAndIP EaIP = new EroAndIP();
EaIP.ero = subERO;
for (int j = 0; j < n; j++)
{
subERO = new ExplicitRouteObject();
boolean hasDomainChanged = false;
if (offset >= ero.getEROSubobjectList().size())
{
return null;
}
while(offset < ero.getEROSubobjectList().size() && !hasDomainChanged)
{
EROSubobject currentERO = ero.getEROSubobjectList().get(offset);
// if ((ero.getEROSubobjectList().get(offset)) instanceof DataPathIDEROSubobject)
// {
// DataPathIDEROSubobject unAux = (DataPathIDEROSubobject)ero.getEROSubobjectList().get(i);
// currentID = reachabilityManager.getDomain(unAux.getRouterID());
//
//
// if (currentID!=null && firstID.equals(currentID))
// {
// subERO.addEROSubobject(currentERO);
// }
// else
// {
// hasDomainChanged = true;
// }
// }
if ((ero.getEROSubobjectList().get(offset)) instanceof UnnumberIfIDEROSubobject)
{
UnnumberIfIDEROSubobject unAux = (UnnumberIfIDEROSubobject)ero.getEROSubobjectList().get(i);
currentID = reachabilityManager.getDomain(unAux.getRouterID());
if (currentID!=null && firstID.equals(currentID))
{
subERO.addEROSubobject(currentERO);
}
else
{
hasDomainChanged = true;
}
}
else
{
subERO.addEROSubobject(currentERO);
}
offset++;
}
try
{
//Make a copy if the Inet4Address variable so there are no problems with pointer
EaIP.address = (Inet4Address) InetAddress.getByAddress(firstID.getAddress());
}
catch (UnknownHostException e)
{
log.info("NO EaIP.address; try EaIP.dataPathID");
EaIP.dataPath = (DataPathID) DataPathID.getByNameBytes(firstID.getAddress());
//log.info(UtilsFunctions.exceptionToString(e));
}
firstID = currentID;
offset--;
}
return EaIP;
}
private class EroAndIP
{
ExplicitRouteObject ero;
Inet4Address address;
DataPathID dataPath;
}
public void encode() throws PCEPProtocolViolationException
{
encode(false);
}
public int getEncodingType()
{
return encodingType;
}
public void setEncodingType(int encodingType)
{
this.encodingType = encodingType;
}
public byte[] getBytes()
{
return messageBytes;
}
public void setMessageBytes(byte[] messageBytes)
{
this.messageBytes = messageBytes;
}
public ReachabilityManager getReachabilityManager()
{
return reachabilityManager;
}
public void setReachabilityManager(ReachabilityManager reachabilityManager)
{
this.reachabilityManager = reachabilityManager;
}
public String toString(){
StringBuffer sb=new StringBuffer(ResponseList.size()*100);
sb.append("RESP: ");
for (int i=0;i<ResponseList.size();++i){
sb.append(ResponseList.get(i).toString());
}
return sb.toString();
}
}