package es.tid.pce.parentPCE;
import java.io.IOException;
import java.net.Socket;
import java.util.Calendar;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Timer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import es.tid.pce.computingEngine.RequestDispatcher;
import es.tid.pce.pcep.PCEPProtocolViolationException;
import es.tid.pce.pcep.constructs.StateReport;
import es.tid.pce.pcep.messages.PCEPClose;
import es.tid.pce.pcep.messages.PCEPInitiate;
import es.tid.pce.pcep.messages.PCEPMessage;
import es.tid.pce.pcep.messages.PCEPMessageTypes;
import es.tid.pce.pcep.messages.PCEPNotification;
import es.tid.pce.pcep.messages.PCEPReport;
import es.tid.pce.pcep.messages.PCEPRequest;
import es.tid.pce.pcep.messages.PCEPResponse;
import es.tid.pce.pcep.objects.ObjectParameters;
import es.tid.pce.pcep.objects.SRP;
import es.tid.pce.pcep.objects.tlvs.ReachabilityTLV;
import es.tid.pce.pcepsession.DeadTimerThread;
import es.tid.pce.pcepsession.GenericPCEPSession;
import es.tid.pce.pcepsession.KeepAliveThread;
import es.tid.pce.pcepsession.PCEPSessionsInformation;
import es.tid.pce.pcepsession.PCEPValues;
import es.tid.rsvp.objects.subobjects.EROSubobject;
import es.tid.tedb.ReachabilityManager;
import es.tid.tedb.TEDB;
/** Thread that maintains a PCEP Session with one PCC Client.
* <p> Reads the first message, and if it is a valid OPEN Message, initiates a new
* PCEP Session </p>
* <p> Then, listens for incoming PCEP messages in a PCEP session and distributes
* them to the appropiate module </p>
* <p> Requests will be forwarded to the RequestQueue, which puts them in a queue
* and are processing by the set of Request Processor Threads </p>
*
* @author Oscar Gonz�lez de Dios
* @author Eduardo Aza��n Teruel
*/
public class ParentPCESession extends GenericPCEPSession{
/**
* Processes topology updates
*/
private MultiDomainTopologyUpdater mdt;
/**
* Timer to schedule KeepWait and OpenWait Timers
*/
/**
* Parent PCE Server General Parameters
*/
private ParentPCEServerParameters params;
private RequestDispatcher requestDispatcher;
private ChildPCERequestManager childPCERequestManager;
private ReachabilityManager rm;
/**
* Used to obtain new request IDs
*/
private static int reqIDCounter=0;
private MultiDomainInitiateDispatcher mdiniDispatcher;
public ParentPCESession(Socket s, ParentPCEServerParameters params, RequestDispatcher requestDispatcher, MultiDomainInitiateDispatcher mdiniDispatcher, TEDB ted, MultiDomainTopologyUpdater mdt, ChildPCERequestManager childPCERequestManager, ReachabilityManager rm, PCEPSessionsInformation pcepSessionManager){
super(pcepSessionManager);
//super("ParentPCESession");
this.setFSMstate(PCEPValues.PCEP_STATE_IDLE);
log=LoggerFactory.getLogger("PCEServer");
log.info("New Parent PCESession: "+s);
this.socket = s;
this.requestDispatcher=requestDispatcher;
this.mdt=mdt;
this.rm=rm;
this.params = params;
timer=new Timer();
this.keepAliveLocal=params.getKeepAliveTimer();
this.deadTimerLocal=params.getDeadTimer();
this.childPCERequestManager=childPCERequestManager;
this.mdiniDispatcher=mdiniDispatcher;
}
/**
* Initiates a Session between the Parent PCE and the peer PCE
*/
public void run() {
initializePCEPSession(params.isZeroDeadTimerPCCAccepted(),params.getMinKeepAliveTimerPCCAccepted(),params.getMaxDeadTimerPCCAccepted(),true,false,null,null,0);
String domain ="hola";//FIXME de donde saco el domain?... SOLO SE puede sacar de la sesion...
childPCERequestManager.registerDomainSession(this.remoteDomainId,this.remotePCEId, out);
//Session is UP now, start timers
log.info("PCE Session succesfully established with "+this.remotePeerIP+" and deadTimerLocal "+this.deadTimerLocal);
this.deadTimerT=new DeadTimerThread(this, this.deadTimerLocal);
startDeadTimer();
this.keepAliveT=new KeepAliveThread(out, this.keepAliveLocal);
startKeepAlive();
//Listen to new messages
while(this.FSMstate==PCEPValues.PCEP_STATE_SESSION_UP) {
try {
this.msg = readMsg(in);//Read a new message
}catch (IOException e){
// cancelDeadTimer();
// cancelKeepAlive();
// timer.cancel();
// try {
// in.close();
// out.close();
// } catch (IOException e1) {
// }
log.warn("Finishing PCEP Session abruptly");
this.killSession();
return;
}
if (this.msg != null) {//If null, it is not a valid PCEP message
boolean pceMsg = true;//By now, we assume a valid PCEP message has arrived
//Depending on the type a different action is performed
switch(PCEPMessage.getMessageType(this.msg)) {
case PCEPMessageTypes.MESSAGE_OPEN:
log.debug("OPEN message received");
//After the session has been started, ignore subsequent OPEN messages
log.warn("OPEN message ignored");
break;
case PCEPMessageTypes.MESSAGE_KEEPALIVE:
log.debug("PCEP KEEPALIVE message received from "+this.remotePeerIP);
//The Keepalive message allows to reset the deadtimer
break;
case PCEPMessageTypes.MESSAGE_CLOSE:
log.debug("CLOSE message received from "+this.remotePeerIP);
try {
PCEPClose m_close=new PCEPClose(this.msg);
log.warn("Closing due to reason "+m_close.getReason());
this.killSession();
} catch (PCEPProtocolViolationException e1) {
log.warn("Problem decoding message, closing session"+e1.getMessage());
this.killSession();
return;
}
return;
case PCEPMessageTypes.MESSAGE_REPORT:
if (this.localPcepCapability.isStateful()) {
log.info("Received report from "+this.remotePeerIP);
PCEPReport pcrpt;
//log.info("Message: "+()msg.toString());
try {
//log.info("Report before");
pcrpt=new PCEPReport(msg);
//log.info("Report after");
Iterator<StateReport> it= pcrpt.getStateReportList().iterator();
while (it.hasNext()){
StateReport sr=it.next();
SRP srp=sr.getSRP();
if (srp!=null) {
//log.info("SRP Id: "+ sr.getSRP().getSRP_ID_number());
Object lock=childPCERequestManager.inilocks.get(sr.getSRP().getSRP_ID_number());
if (lock!=null){
synchronized (lock) {
childPCERequestManager.notifyReport(sr);
}
}
}
}
} catch (PCEPProtocolViolationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
break;
}
}else {
log.warn("PCE is NOT stateful, ignored report from "+this.remotePeerIP);
}
break;
case PCEPMessageTypes.MESSAGE_ERROR:
log.debug("ERROR message received");
//Up to now... we do not do anything in the server side
break;
case PCEPMessageTypes.MESSAGE_NOTIFY:
PCEPNotification m_not;
try {
m_not=new PCEPNotification(this.msg);
for (int i=0;i<m_not.getNotifyList().size();++i){
int notifType=m_not.getNotifyList().get(i).getNotificationList().get(0).getNotificationType();
if (notifType==ObjectParameters.PCEP_NOTIFICATION_TYPE_PENDING_REQUEST_CANCELLED){
//Need to cancel request...
}
else if (notifType==ObjectParameters.PCEP_NOTIFICATION_TYPE_REACHABILITY){
log.info("Reachability Notification received");
LinkedList<ReachabilityTLV> reachabilityTLVList=m_not.getNotifyList().get(i).getNotificationList().get(0).getReachabilityTLVList();
//DomainIDTLV domainIDTLV ==m_not.getNotifyList().get(i).getNotificationList().get(0).g
if (reachabilityTLVList!=null){
log.debug("Reachability TLV List not null and size "+reachabilityTLVList.size());
for (int ii=0;ii<reachabilityTLVList.size();++ii){
LinkedList<EROSubobject> EROSubobjectList= reachabilityTLVList.get(ii).getEROSubobjectList();
log.debug("EROSubobjectList size "+EROSubobjectList.size());
for (int jj=0;jj< EROSubobjectList.size();++jj){
//rm.addEROSubobject(remoteDomainId, reachabilityTLVList.get(ii).EROSubobjectList.get(jj));
}
}
}else {
log.info("Reachability TLV NULL");
}
}
else if (notifType==ObjectParameters.PCEP_NOTIFICATION_TYPE_TOPOLOGY){
log.debug("Topology Notification received");
//mdt.processNotification(m_not.getNotifyList().get(i).getNotificationList().get(0),this.remotePCEId,this.remoteDomainId);
}
else if (notifType==ObjectParameters.PCEP_NOTIFICATION_TYPE_IT_RESOURCE_INFORMATION){
mdt.processNotification(m_not.getNotifyList().get(i).getNotificationList().get(0),this.remotePCEId,this.remoteDomainId);
}
}
} catch (PCEPProtocolViolationException e1) {
log.warn("Problem decoding notify message, ignoring message"+e1.getMessage());
e1.printStackTrace();
}
//FIXME: COMPLETARRRRR
break;
case PCEPMessageTypes.MESSAGE_PCREP:
log.info("Received PC RESPONSE message");
PCEPResponse pcres;
try {
pcres=new PCEPResponse(msg);
log.info("IdResponse: "+pcres.getResponse(0).getRequestParameters().getRequestID());
synchronized (childPCERequestManager.locks.get(pcres.getResponse(0).getRequestParameters().getRequestID())) {
childPCERequestManager.notifyResponse(pcres);
}
} catch (PCEPProtocolViolationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
break;
}
break;
case PCEPMessageTypes.MESSAGE_PCREQ:
log.info("PCREQ message received");
PCEPRequest p_req;
try {
p_req=new PCEPRequest(msg);
log.info(p_req.toString());
} catch (PCEPProtocolViolationException e) {
e.printStackTrace();
break;
}
requestDispatcher.dispathRequests(p_req,out,this.remotePCEId);
break;
case PCEPMessageTypes.MESSAGE_INITIATE:
log.info("PCINI message received from "+this.remotePeerIP);
PCEPInitiate p_ini;
try {
p_ini=new PCEPInitiate(msg);
log.info(p_ini.toString());
} catch (PCEPProtocolViolationException e) {
e.printStackTrace();
break;
}
this.mdiniDispatcher.dispathInitiate(p_ini,out,this.remotePeerIP );
break;
default:
log.warn("ERROR: unexpected message from "+this.remotePeerIP);
pceMsg = false;
}
if (pceMsg) {
log.debug("Reseting Dead Timer as PCEP Message has arrived in "+this.remotePeerIP);
resetDeadTimer();
}
}
}
}
// public void killSession(){
// log.warn("Killing Session");
// childPCERequestManager.removeDomain(this.remoteDomainId);
// timer.cancel();
// this.endConnections();
// this.cancelDeadTimer();
// this.cancelKeepAlive();
// this.endSession();
// log.warn("Interrupting thread!!!!");
// this.interrupt();
// }
//
public void endSession(){
log.error("Removing domain "+this.remoteDomainId+" due to endSession from "+this.remotePeerIP);
childPCERequestManager.removeDomain(this.remoteDomainId);
}
/**
* USE THIS COUNTER TO GET NEW IDS IN THE REQUESTS
* @return reqid int
*/
synchronized static public int getNewReqIDCounter(){
int newReqId;
if (reqIDCounter==0){
Calendar rightNow = Calendar.getInstance();
newReqId=rightNow.get(Calendar.SECOND);
reqIDCounter=newReqId;
}
else {
newReqId=reqIDCounter+1;
reqIDCounter=newReqId;
}
return newReqId;
}
}