/*
 * Copyright (C) 2008 The Trustees of Columbia University in the City of New York. 
 * All rights reserved.
 *
 * See the file LICENSE included in this distribution for details.
 */

#include "kadpeer.h"

#ifndef _WENGO
#include "kadrtable.h"
#include "trace.h"
#endif

#ifdef _WENGO
#include "p2pp/table/kadrtable.h"
#include "p2pp/common/trace.h"
#endif

#include "stimanager.h" 

KadPeer::KadPeer() {

}


KadPeer::~KadPeer() {

}


void KadPeer::Initialize() {

  m_pRT = new KadRTable;
  m_pKRT = (KadRTable*)m_pRT;

  //set peer pointer in routing table
  m_pKRT->setParams(this);
  
  m_pNT = NULL; //There is no neighbor table in Kademlia

  //TEMP: Set NodeId, hashalg, and base in routing table
  if(m_ID[0]!=0){
    m_pKRT->setNodeId(m_ID, 20, 2);
  }
  //      m_pKRT->setNodeId(m_ID, m_msg.stp2poptions.halglen, m_msg.stp2poptions.hbase);

  //Init TURN server
  //m_objSTI.InitializeServer();

  Peer::Initialize();  

}//Initialize



/*
  0 then this is the hop
  otherwise 302
*/
uint32 KadPeer::getNextHop(uchar* peerid, uint32 len, struct peerinfo& stP) {

  return m_pKRT->getNextHop(peerid, len, stP);
}//getNextHop



void KadPeer::OnTimer() {

  map<string, Transaction*>::iterator itr;
  list<string> lint;
  list<string>::iterator litr;
  list<LObject>::iterator i1;
  struct peerinfo stP;
  struct LObject objLO;
  
  struct peerinfo tp;

  int32 ret;


  TRACE(5,"KadPeer::OnTimer...transaction map: %d LObject map: %d\n", m_TMap.size(), m_LO.size() );


  //CODE FOR interacting with command line
  for(i1=m_LO.begin(); i1 != m_LO.end(); i1++) {
    if( (*i1).ritype == ePUBLISHOBJECT) {

      if( (*i1).changeID == 0) {
        m_objRM.PublishObject( (char*)(*i1).strKey.c_str(), (*i1).strKey.size(), (char*)(*i1).strVal.c_str(), (*i1).strVal.size(), (*i1).tt, (*i1).callback, (*i1).pApp);
      } else {
        m_objRM.ChangeUserID( (char*)(*i1).strKey.c_str(), strlen( (char*)(*i1).strKey.c_str()) );
      }

    } else if((*i1).ritype == eLOOKUPOBJECT) {
      
      if( (*i1).conttype == eSTRINGVAL) {
        m_objRM.LookupObject((char*)(*i1).strKey.c_str(), (*i1).strKey.size(), (*i1).tt, (*i1).callback, (*i1).pApp);
      } else if( (*i1).conttype == eUSERINFO ) {
        m_objRM.LookupUser((char*)(*i1).strKey.c_str(), (*i1).strKey.size(), (*i1).tt, (*i1).callback, (*i1).pApp);
      } else if( (*i1).conttype == eSIP ) {
        m_objRM.LookupSIP((char*)(*i1).strKey.c_str(), (*i1).strKey.size(), (*i1).tt, (*i1).callback, (*i1).pApp);
      }
    } else if( (*i1).ritype == eGETDIAGNOSTICS ) {
      m_objMH.GetDiagnostics( (char*)(*i1).pchIP, (*i1).port, (*i1).tt, (*i1).diagtype, (*i1).callback, (*i1).pApp );
    } else if ( (*i1).ritype == eLEAVE ) {
      if( 1 == (*i1).disconnect) {
        m_eState = ePDISCONNECTED;

        //create a copy of call back function
        objLO.callback = (*i1).callback;
        objLO.pApp = (*i1).pApp;
        break;
      }
    } 
    
  }//end for

  m_LO.clear();
  //CODE FOR interacting with command line ENDS
  

  ////////////////////////////////////////////////////////////////////  
  //  Process transaction maps starts
  ////////////////////////////////////////////////////////////////////
  
  if(ePDISCONNECTED != m_eState ) {

    //Transaction management code BEGINS
    //Check if transaction has timedout
    for(itr=m_TMap.begin(); itr!=m_TMap.end(); itr++) {
      
      ret = itr->second->OnTimer();
      
      //the transaction has expired
      if(0 == ret) {
	      OnTransactionTimeout(itr->second);
	
	      TRACE(2, "KadPeer::OnTimer...deleting transaction state: %d\n", m_eState);
	
        //The transaction was allocated so it must be deleted
        delete itr->second;
        lint.push_back(itr->first);
      }
      
    }//end for
  
  
    for(litr=lint.begin(); litr!=lint.end(); litr++) {
      itr = m_TMap.find(*litr);
      if(itr != m_TMap.end() ) {
        m_TMap.erase(itr);
      }
    }//end for
    //Transaction management code ENDS

  } else {

    TRACE(2, "KadPeer::OnTimer...deleting transaction state: %d (DISCONNECTED) map size: %d\n", m_eState, m_TMap.size() );
    
    for(itr=m_TMap.begin(); itr!=m_TMap.end(); itr++) {	
      //The transaction was allocated so it must be deleted
      delete itr->second;
    }//end for  

    //remove all transactions from map
    m_TMap.clear();
  }


  ////////////////////////////////////////////////////////////////////  
  //  Process transaction maps ENDS
  ////////////////////////////////////////////////////////////////////



  switch(m_eState) {
    
  case ePBOOTSTRAP:
    ComposeBootstrap();
    m_eState = ePBOOTSTRAPSENT;
    break;
    
  case ePINITIAL:
    break;
    
  case ePCONNECTED:
    
    if( isTTExpired() ) {
      TRACE(4, "KadPeer::OnTimer...TT timer expired\n", "");

      //Apply timer to resource object
      m_objRM.OnTimer();

      //TEMP commented
      m_pKRT->OnTimer();
      
      setTTTimer();
    }
    
    break;

  case ePDISCONNECTED:
    TRACE(1, "KadPeer::OnTimer...Transport disconnecting\n", "");
    m_pobjTransport->Disconnect();
    
    m_objMH.Disconnect(); //Maintenance helper disconnect    
    m_objRM.Disconnect(); //Resource manager disconnect
    m_pKRT->Disconnect(); //Routing table disconnect

    delete m_pKRT; //delete the routing table object

    m_BSP.clear();  //clear the bootstrap list

    objLO.callback( (void*)&objLO, 200);
    break;

  default:
    break;

  }//end switch


  Peer::OnTimer();
  
  TRACE(5, "KadPeer::OnTimer\n", "");

}//OnTimer



void KadPeer::OnTransactionTimeout(Transaction* pobjTrans) {

  struct peerinfo stpeer;
  struct LObject objLO;
  struct timeval cur_time;

  //remove the failed peer from routing table. 
  //Maybe not remove immediately?
  //BIG JUGAR
  while(1==m_pKRT->RemovePeer(pobjTrans->m_pchIP, pobjTrans->m_uiPort) );

  TRACE(2, "KadPeer::OnTransactionTimeout...state %d size: %d\n", m_eState, m_BSP.size() );  

  
  switch(m_eState) {

  case ePBOOTSTRAPSENT:
    TRACE(1, "KadPeer::OnTransactionTimeout...Bootstrap failed\n", "");
    objLO.ritype = eBOOTSTRAP;
    objLO.pApp = m_pApp;
    
    appCallBack( (void*)&objLO, 400);
    break;

  case ePLOOKUPSTUN:

    //the painful join process
    m_eSubState = eS_PNONE;
	
    TRACE(2, "Client::OnTransactionTimeout...LookupSTUN failed: %s\n", m_itrSTind->staddr.addr[0] );

    //remove the failed STUN server
    m_BSP.erase(m_itrSTind);    
	
    if(m_BSP.size() == 0) {
      m_eState = ePCONNECTED;

      setTTTimer();

      printf("Connected state. There is only ONE peer in the overlay.\n");        
      printf("JOIN SUCCESSFUL === Peer-Id: 0x");
      for(int i=0; i<idlen; i++) {
        printf("%02x", m_ID[i]);
      }
      printf("\n");

      //Fix for the case when there is only one peer in network
      //perform not nat detection
      STIManager::m_eNatType = PJ_STUN_NAT_TYPE_OPEN;

      //Insert itself as a resource-object in its own
      //resource-object
      //FIXME: transport is UDP. Should it be TCP
      m_objRM.PublishUserInfo( (char*)m_USERID, strlen((char*)m_USERID), eUDP );

    } else {

      //Among the bootstrap candidates returned, randomly select a one
      //and lookup STUN server port. At present, the STUN server to which a 
      //request is sent simply returns itself.
    
      objLO.conttype = eSTUN_PORT;
      gettimeofday(&cur_time, NULL);
      srand(cur_time.tv_usec);
      int rndmIndex=rand()%(m_BSP.size());
      for(list<peerinfo>::iterator litr=m_BSP.begin(); litr!=m_BSP.end(); litr++) {
        if(rndmIndex==0) {
          m_objRM.LookupStunPort( *litr, eUDP ) ;
          m_itrSTind = litr;
          break;
	    }
        rndmIndex--;
      }//end for
    }
    break;

  case ePJOIN:
    
    TRACE(2, "KadPeer::OnTransactionTimeout...size: %d\n", m_BSP.size() );    

    //pop it from the stack
    m_BSP.pop_front();

    if(m_BSP.size() > 0) {
      
      stpeer = *m_BSP.begin();
      TRACE(2, "KadPeer::OnTransactionTimeout...Sending Join...BSP...size: %d\n", m_BSP.size() );
      ComposeJoin(*m_BSP.begin());

    } else {
      m_eState = ePCONNECTED;

      setTTTimer();

      printf("Connected state. There are MORE THAN one peers in the overlay.\n");        
      printf("JOIN SUCCESSFUL === Peer-Id: 0x");
      for(int i=0; i<idlen; i++) {
        printf("%02x", m_ID[i]);
      }
      printf("\n");

      //Insert itself as a resource-object in its own
      //resource-object
      //FIXME: transport is UDP. Should it be TCP
      m_objRM.PublishUserInfo( (char*)m_USERID, strlen((char*)m_USERID), eUDP );
    }//end if

    break;
    

  case ePCONNECTED:
    m_objRM.OnTransactionTimeout(pobjTrans->m_msgtype, pobjTrans->m_reqoritype, pobjTrans->getTransId(), pobjTrans->m_pchIP, pobjTrans->m_uiPort);

    //Maintenance helper transaction timeout
    m_objMH.OnTransactionTimeout(pobjTrans->m_msgtype, pobjTrans->m_reqoritype, pobjTrans->getTransId(), pobjTrans->m_pchIP, pobjTrans->m_uiPort);
    break;

  default:
    break;
  }//end switch  

}//OnTransactionTimeout



int32 KadPeer::OnReceive(uchar* buf, int len, char* pchIP, int32 port, transtype tt) {

  int32 ret;
  map<string, Transaction*>::iterator itr;
  struct sockaddr_in staddr;
  int addrlen;

  //Check if packet is STUN. If it is, parse it and process it.
  if(STIManager::IsStunPacket(buf, len)) {
    getSockAddr_in(pchIP, port, &staddr); 
    addrlen=sizeof(staddr);
    m_objSTI.ParseStunPacket(buf, len, &staddr, &addrlen,m_pobjTransport->getUDPSocket(), eSOCK_P2PP);
    return 1 ;
  } 
    
  //Initialize the message structure
  m_msg.Initialize();

  TRACE(2, "KadPeer::OnReceive...received from IP address: %s port: %d\n", pchIP, port);

  //Parse the message
  ret = m_msg.parse(buf, len);

  if(-1 == ret) {
    TRACE(1, "KadPeer::OnReceive...parse error. length is: %d\n", len);
    return 1;
  }

  
  
  TRACE(2, "KadPeer::OnReceive...received transid: %s\n", (char*)m_msg.getTransId().c_str() );

  
  TRACE(2, "KadPeer::OnReceive...state: %d msgtype: %s\n", m_eState, pmsgtype[m_msg.stcmn_hdr.msgtype]);
  

  //At this point ACKs and retransmissions have been matched to the
  //existing transactions. So we have only new requests, response,
  //responseACK, and indications at this point. Now process them.  

  //if ACK
  if(1 == m_msg.stcmn_hdr.ack ) {
    OnACK(pchIP, port, tt);
  } else if(eREQUEST == m_msg.stcmn_hdr.msgtype) {    
    OnRequest(pchIP, port, tt);
  } else if(eRESPONSE == m_msg.stcmn_hdr.msgtype || eRESPONSEACK == m_msg.stcmn_hdr.msgtype) {
    return OnResponse(pchIP, port, tt);
  } else if(eINDICATION == m_msg.stcmn_hdr.msgtype) {
    OnIndication(pchIP, port, tt);
  }
  
  //Call Peer::OnReceive
  return Peer::OnReceive(buf, len, pchIP, port, tt);
  
}//OnReceive




int32 KadPeer::OnACK(char* pchIP, int32 port, transtype tt) {
  map<string, Transaction*>::iterator itr;

  //Find the transaction
  itr=m_TMap.find(m_msg.getTransId());

  //If transaction does not exist, discard the ACK
  if(itr==m_TMap.end() ) {
    TRACE(2, "KadPeer::OnACK...ACK received...transaction does not exist %d\n", m_msg.stcmn_hdr.transid);
    return 1;
  }
     
  switch(m_msg.stcmn_hdr.msgtype) {
      
  case eREQUEST:
    if(eREQUEST == itr->second->m_msgtype) {
      TRACE(1, "KadPeer::OnACK...ACK received for REQUEST\n", "" );
      itr->second->OnACK(m_msg);
    } else {
      TRACE(1, "KadPeer::OnACK...expecting ACK for REQUEST but received otherwise\n", "" );
    }
    break;

  case eRESPONSE:
  case eRESPONSEACK:
  case eINDICATION:

    if(eRESPONSE == itr->second->m_msgtype || eRESPONSEACK == itr->second->m_msgtype || 
       eINDICATION == itr->second->m_msgtype) {

      TRACE(1, "KadPeer::OnReceive....ACK received for RESPONSE, RESPONSEACK or INDICATION...Transaction size: %d\n", m_TMap.size() );
      delete itr->second;
      m_TMap.erase(itr);
      TRACE(2, "KadPeer::OnReceive.....Transaction removed size: %d\n", m_TMap.size() );
    } else {
      TRACE(2, "KadPeer::OnACK...expecting ACK for RESP, RESPACK, INDIC but received otherwise\n", "" );
    }
    break;

  default:
    break;
  }//end switch
  

  return 1;
}//OnACK



int32 KadPeer::OnRequest(char* pchIP, int32 port, transtype tt) {

  struct peerinfo stPSelf, stPNext;
  list<peerinfo> lstP;
  map<string, Transaction*>::iterator itr;
  list<resourceobject > lstro;

  //Find the transaction
  itr=m_TMap.find(m_msg.getTransId());
  
  //retransmission of request received for which response transaction
  //already exists. ignore.
  if(itr != m_TMap.end() && (eRESPONSE == itr->second->m_msgtype || 
                             eRESPONSEACK == itr->second->m_msgtype) ) {

    TRACE(1, "KadPeer::OnRequest...retransmission of request received for which a response transaction already exists", "");
    return 0;
    
  }//end if
  

  switch(m_eState) {

  case ePCONNECTED:

    switch(m_msg.stcmn_hdr.reqoritype) {

    case eJOIN:
      m_objMH.OnJoinRequest(m_msg, pchIP, port, tt);
      break;

    case eLEAVE:
      break;

    case eKEEPALIVE:
      if(ePEER == m_msg.stcmn_hdr.porc) {
	//update keep-alive timer
        m_pKRT->Insert(m_msg.stpeerinfo, 1);
      } else {
	//printf("Received from a client\n");
      }
      ComposeKeepAliveResp(pchIP, port, tt);
      break;

    case eEXCHANGETABLE:
      //gettable
      if(m_msg.stpeerinfo.strtt.isPresent==1) {
        m_pKRT->updateRTT(m_msg.stpeerinfo);
      }//if
      m_pKRT->getTable(lstP, tt);
      ComposeExchangeTableResp(lstP, pchIP, port, tt);
      break;

    case eGETDIAGNOSTICS:
      //gettable
      m_pKRT->getTable(lstP, tt);
      m_objRM.getResTable(lstro, tt);
      ComposeDiagnosticsResp(lstP, lstro, pchIP, port, tt);
      break;

    case ePUBLISHOBJECT:
      //can we insert the peerinfo object in our own routing table?
      //insert in routing table only if peer
      if(ePEER == m_msg.stcmn_hdr.porc) {	
        m_pKRT->Insert(m_msg.stpeerinfo, 1);
      }

      m_objRM.OnPublishObjectRequest(m_msg, pchIP, port, tt);
      break;

    case eLOOKUPOBJECT:
      //can we insert the peerinfo object in our own routing table?
      //insert in routing table only if peer
      if(ePEER == m_msg.stcmn_hdr.porc) {
        m_pKRT->Insert(m_msg.stpeerinfo, 1);
      }

      m_objRM.OnLookupObjectRequest(m_msg, pchIP, port, tt);
      break;

    case eLOOKUPPEER:
      //can we insert the peerinfo object in our own routing table?
      //insert in routing table only if peer
      if(ePEER == m_msg.stcmn_hdr.porc) {
        m_pKRT->Insert(m_msg.stpeerinfo, 1);
      }

      m_objMH.OnLookupPeerRequest(m_msg, pchIP, port, tt);
      break;

    case eSET:
      m_objMH.OnSetRequest(m_msg, pchIP, port, tt);
      break;

    case eRESET:
      m_objMH.OnResetRequest(m_msg, pchIP, port, tt);
      break;

    default:
      break;
    }//end switch
    break;
    
  default:
    break;

  }//end switch

  return 1;
  
}//OnRequest



int32 KadPeer::OnResponse(char* pchIP, int32 port, transtype tt) {

  struct peerinfo stP, tstP1;
  list<peerinfo>::iterator litr;
  map<string, Transaction*>::iterator itr;
  enum msgtype mtype;
  struct LObject objLO;
  string strtransid;
  struct resourceobject ro;
  map <string, port_trans> addrmap;
  map <string, port_trans>::iterator itr2;
  struct timeval cur_time;

  //If received over unreliable transport send the ACK immediately
  if(tt == eUDP || tt == eDTLS) {   
    ComposeACK(pchIP, port);
  }

  //Find the transaction
  itr=m_TMap.find( m_msg.getTransId() );

  TRACE(1, "KadPeer::OnResponse...Transaction map size: %d state: %d\n", m_TMap.size(), m_eState ); 

  //response or responseACK received. check for matched requests or responses
  if(itr != m_TMap.end() ) {

    //added for windows
    mtype = itr->second->m_msgtype;

    //If response matches to a request delete the request transaction
    if(eREQUEST == itr->second->m_msgtype ) {
      char temp[2*HASHLEN];
      string dstId;  
      uchar_to_hexstring(m_msg.stpeerinfo.stpeerid.id, idlen, temp);
      dstId=temp;
      
      if(0 != strcmp(itr->second->m_dstId.c_str(),dstId.c_str() ) && itr->second->m_reqoritype == eKEEPALIVE) {
	//printf("JUGAR \n%s\n%s\n", itr->second->m_dstId.c_str(), dstId.c_str());
	m_pKRT->RemoveId(itr->second->m_uchdstId, idlen );
      }

      delete itr->second;
      m_TMap.erase(itr);

      TRACE(1, "KadPeer::OnResponse.....Transaction terminated. size: %d\n", m_TMap.size() );
    }

    //If response matches to a response or responseACK transaction,
    //then we have received a retransmission of response. Ignore
    if(eRESPONSE == mtype || eRESPONSEACK == mtype) {

      TRACE(1, "KadPeer::OnResponse.....retransmission of response received %s\n", m_msg.getTransId().c_str() );
      return 1;
      
    }//end if

  } else {
    TRACE(1, "KadPeer::OnResponse.....Transaction does not exist %d\n", m_TMap.size() );
    return 1;
  }

  switch(m_eState) {    
    
  case ePBOOTSTRAPSENT:
    if(eBOOTSTRAP==m_msg.stcmn_hdr.reqoritype) {
      
      //Update global idlen
      idlen = m_msg.stp2poptions.halglen;
      
      getSelfID();
      
      TRACE(2, "KadPeer::OnResponse...Bootstrap...num peers: %d\n", m_msg.stlpeerinfo.size() );
      
      //TEMP: Set NodeId, hashalg, and base in routing table
      m_pKRT->setNodeId(m_ID, m_msg.stp2poptions.halglen, m_msg.stp2poptions.hbase);
      
      //Create bootstrap node list
      CreateBNList(m_BSP);

      //Check if another node was returned. If we are the only node,
      //then stlpeerinfo should be one.
      if(m_msg.stlpeerinfo.size() <= 1) {

        m_eState = ePCONNECTED;

        setTTTimer();

        printf("Connected state. There is only ONE peer in the overlay.\n");
        printf("JOIN SUCCESSFUL === Peer-Id: 0x");
        for(int i=0; i<idlen; i++) {
          printf("%02x", m_ID[i]);
        }
        printf("\n");


        //We are now connected. Init TURN server
	      m_pobjTransport->getAddrPort(addrmap);
	      itr2=addrmap.begin();
	      uint16 srvport=m_objSTI.GetServerPort();
        getSelfPeer(stP);
	      m_objSTI.Initialize((char8 *)itr2->first.c_str(), srvport, stP, m_BSP, itr2->first.c_str());

        //Fix for the case when there is only one peer in network
        //perform not nat detection
        STIManager::m_eNatType = PJ_STUN_NAT_TYPE_OPEN;

        m_objSTI.InitializeServer();

        //Insert itself as a resource-object in its own
        //resource-object
        //FIXME: transport is UDP
        m_objRM.PublishUserInfo( (char*)m_USERID, strlen((char*)m_USERID), eUDP );
       
        //inform the application
        objLO.ritype = eBOOTSTRAP;
        objLO.pApp = m_pApp;
        if(appCallBack){
          appCallBack( (void*)&objLO, 200);
        }
      } else {
        //the painful join process
	    m_eState = ePLOOKUPSTUN;
	    m_eSubState = eS_PNONE;
	
        TRACE(2, "Client::OnResponse...Bootstrap...num peers: %d\n", m_msg.stlpeerinfo.size() );
	
        //Among the bootstrap candidates returned, randomly select a one
        //and lookup STUN server port. At present, the STUN server to which a 
        //request is sent simply returns itself.
    
        objLO.conttype = eSTUN_PORT;
        gettimeofday(&cur_time, NULL);
        srand(cur_time.tv_usec);
        int rndmIndex=rand()%(m_BSP.size());
        for(litr=m_BSP.begin(); litr!=m_BSP.end(); litr++) {
          if(rndmIndex==0) {
            m_objRM.LookupStunPort( *litr, eUDP ) ;
            m_itrSTind = litr;
            break;
	      }
	      rndmIndex--;
		}//end for

      }//else
    }
    break;

  case ePLOOKUPSTUN:
    //store the stun server response
    if(200 == m_msg.stcmn_hdr.respcode) {
      
      ro=*(m_msg.lstro.begin());
      strncpy(m_STUN_IP, ro.staddr.addr[0],IPADDRLEN);
      m_STUN_PORT=ro.staddr.port[0];
      
      printf("STUN server found: %s:%d\n", (char*)m_STUN_IP, m_STUN_PORT);
      
      //initialize STI manager
      m_pobjTransport->getAddrPort(addrmap);
      itr2=addrmap.begin();

      //put the randomly selected STUN server at the top of BSP list.
      tstP1 = *m_itrSTind;
      m_BSP.erase(m_itrSTind);
      m_BSP.push_front(tstP1);

      m_objSTI.Initialize(m_STUN_IP, m_STUN_PORT, ro.stpeerinfo, m_BSP, itr2->first.c_str());
      m_objSTI.InitializeClient(m_pobjTransport->getUDPSocket(), itr2->first.c_str(), itr2->second.port);
      //find NAT type and return if behind NAT      
    }
    m_eState = ePJOIN;
    m_eSubState = eS_PNONE;
    

    if(m_objSTI.getNatType()!=PJ_STUN_NAT_TYPE_OPEN && m_NODE_TYPE == eAUTO) {
      //exit client mode and enter peer mode
      m_NODE_TYPE=eCLIENT;
      ComposeJoin( *(m_BSP.begin()) );
      printf("Node is behind NAT. Joining as CLIENT\n");
      TRACE(1, "KadPeer::OnResponse...Node is behind NAT. Joining as client\n", "");
      return 0;
    } else {
      ComposeJoin( *(m_BSP.begin()) );
    }    
    break;
    
  
  case ePJOIN:
    
    switch(m_eSubState){
      
    case eS_PNONE:

      if(302 == m_msg.stcmn_hdr.respcode) {
        TRACE(2, "KadPeer::OnResponse...302 for Join...Send Join\n", "");
	
        //Insert the peer in routing table
        m_pKRT->Insert(m_msg.stpeerinfo, 1);

        //if there is a 302 present
        if(m_msg.stlpeerinfo.size() > 0) {
          litr=m_msg.stlpeerinfo.begin();

          printf("302 response %s %d\n", m_msg.stpeerinfo.staddr.addr[0], m_msg.stpeerinfo.staddr.port[0]);

          ComposeJoin(*litr);
        } else {
          printf("Error in Join...There was no peerinfo object in 302\n");
        }        

      } else if(200 == m_msg.stcmn_hdr.respcode) {
        TRACE(2, "KadPeer::OnResponse...200 for Join\n", "");
        m_eState = ePCONNECTED;

        printf("Connected state. There are MORE THAN one peers in the overlay.\n");
        printf("JOIN SUCCESSFUL === Peer-Id: 0x");
        for(int i=0; i<idlen; i++) {
          printf("%02x", m_ID[i]);
        }
        printf("\n");

        //Insert the peer in routing table
        m_pKRT->Insert(m_msg.stpeerinfo, 1);

        //Set the routing table timer
        setTTTimer();

        //get a copy of the peerinfo object received
        stP = m_msg.stpeerinfo;

        //Now we are connected. Initialize the TURN server.
        m_objSTI.InitializeServer();

        //inform the application
        objLO.ritype = eBOOTSTRAP;
        objLO.pApp = m_pApp;
        if(appCallBack){
          appCallBack( (void*)&objLO, 200);
        }
        //Insert itself as a resource-object in its own
        //resource-object
        //FIXME: transport is UDP
        m_objRM.PublishUserInfo( (char*)m_USERID, strlen((char*)m_USERID), eUDP );

        //get the routing table of the node
        ComposeExchangeTable(stP);
      }
      break;

    case eS_PTUPDATE:
      break;

    default:
      break;
    }//end switch

    break; //end join

  case ePCONNECTED:    
    {
      switch(m_msg.stcmn_hdr.reqoritype) {

      case eJOIN:
        m_objMH.OnJoinResponse(m_msg);
        break;

      case eEXCHANGETABLE:
        //send keep-alives 
        //m_objMH.OnExchangeTable(m_msg.strt.table);
        //m_pKRT->Insert(m_msg.strt.table, 0);
	
        m_pKRT->OnExchangeTable(m_msg.strt.table);
        m_pKRT->updateRTT(m_msg.stpeerinfo);
        break;

      case eGETDIAGNOSTICS:
        m_objMH.OnGetDiagnosticsResponse(m_msg);
        break;
        
      case ePUBLISHOBJECT:
        //m_pKRT->Insert(m_msg.strt.table);
        m_objRM.OnPublishObjectResponse(m_msg);
        break;

      case eLOOKUPOBJECT:
        m_objRM.OnLookupObjectResponse(m_msg);
        break;

      case eKEEPALIVE:
        //called to update our last seen timer
        m_pKRT->Insert(m_msg.stpeerinfo, 1);
        m_pKRT->updateRTT(m_msg.stpeerinfo);
        break;

      case eLOOKUPPEER:
        //called to update our last seen timer
        m_pKRT->Insert(m_msg.stpeerinfo, 1);
        break;

      default:
        break;

      }//end switch
        
      
    }//case ePCONNECTED
    
    break;

  default:
    break;

  }//end switch
  

  return 1;

}//OnResponse



int32 KadPeer::OnIndication(char* pchIP, int32 port, transtype tt) {

  return 1;
  
}//OnIndication


int32 KadPeer::Insert(struct peerinfo& stP, int32 updateKA){
  m_pKRT->Insert(stP, updateKA);
  return 1;
}//Insert


int32 KadPeer::Insert(list<peerinfo>& lstP, int32 updateKA){
  m_pKRT->Insert(lstP, updateKA);
  return 1;
}//Insert

int32 KadPeer::Insert(struct peerinfo& stP, int32 updateKA, uint16 stunPort) {
  m_pKRT->Insert(stP, updateKA, stunPort);
  return 1;
}//Insert


void KadPeer::setTTTimer() {
  gettimeofday(&m_tTT, NULL);
  m_tTT = addtimeval(m_tTT, m_TT, 0);
}//setTTTimer


int32 KadPeer::isTTExpired() {
  struct timeval cur, difft;
  gettimeofday(&cur, NULL);

  //difference between timer and current time
  difft = difftimeval(m_tTT, cur);

  if(0 == difft.tv_sec && 0 == difft.tv_usec) {
    return 1;
  }//end if
  
  return 0;
  
}//isTTExpired




void KadPeer::ShowRT() {

  struct peerinfo stP;

  printf("Peer::showrt\n");

  getSelfPeer(stP);

  printf("\n");
  printf("Node Id: 0x");
  
  for(int i=0; i<m_HASH_SIZE; i++) {
    printf("%x", m_ID[i]);
  }
  printf(" %s %d\n", stP.staddr.addr[0], stP.staddr.port[0]);
  printf("Routing Table\n");
  printf("-------------\n");

  m_pKRT->Show();

}//ShowRT

void KadPeer::ShowNT() {

  //m_pKNT->Show();

}//ShowNT


void KadPeer::ShowRO() {

  m_objRM.ShowRO();

}//ShowRO

int32 KadPeer::GetSIPObject(struct resourceobject& stRo) {

  map<string, port_trans> addrmap;
  map<string, int> relaymap;
  map<string, port_trans>::iterator itr;
  map<string, int>::iterator itrrelay;

  stRo.isPresent=1;
  stRo.conttype=eSIP;
  stRo.staddr.isPresent=1;
  stRo.staddr.num=1;

  relaymap.clear();
  //add relay address
  int i=0;
  m_objSTI.GetRelayAddr(5060, relaymap);
  if(relaymap.size()) {
    for(itrrelay=relaymap.begin(); itrrelay!=relaymap.end(); itrrelay++, i++) {
      
      strncpy(stRo.staddr.addr[i], (char*)itrrelay->first.c_str(), 16);
      stRo.staddr.port[i] = itrrelay->second;
      stRo.staddr.tt[i]   = eUDP;
      stRo.staddr.ht[i]   = eRELAYED;
      stRo.staddr.ipver[i]=4;
      
      stRo.staddr.R[i] = 0;
      stRo.staddr.foundation[i] = 0;
      stRo.staddr.compid[i] = 0;
      stRo.staddr.priority[i] = 0;
      
    }//end for
  } else {
    //Get the addressinfo object from transport
    m_pobjTransport->getAddrPort(addrmap);
    for(itr=addrmap.begin(); itr!=addrmap.end(); itr++, i++) {
      
      strncpy(stRo.staddr.addr[i], (char*)itr->first.c_str(), 16);
      stRo.staddr.port[i] = 5060;
      stRo.staddr.tt[i]   = itr->second.tt;
      stRo.staddr.ht[i]   = itr->second.ht;
      stRo.staddr.ipver[i]=4;
      
      stRo.staddr.R[i] = 0;
      stRo.staddr.foundation[i] = 0;
      stRo.staddr.compid[i] = 0;
      stRo.staddr.priority[i] = 0;
      
    }//end for
  }//end if

  return 1;
}//GetSIPObject

void KadPeer::UpdateRelayList(list<peerinfo>& lstP){
  //m_objSTI.UpdateRelayList(lstP);
}

int KadPeer::GetStunServerPort() {
  return m_objSTI.GetServerPort();
}

void KadPeer::ShowTURNAlloc() {
  print_server_resource_usage();
}//Kadpeer::showTURNAlloc
