#include "nrlolsr.h"


Nrlolsr::Nrlolsr(ProtoSocket::Notifier& theNotifier, ProtoTimerMgr& theTimer) : socket(ProtoSocket::UDP)
{ 
  timerMgrPtr = &theTimer;

 //DMSG(6,"Enter: Nrlolsr::Nrlolsr()\n");
  socket.SetNotifier(&theNotifier); 
  socket.SetListener(this,&Nrlolsr::OnSocketEvent);

  Neighb_Hold_Time = 6.0; //is default value changed on Start();
  qosvalue=0;
  userDefBroadcast = false;

  ipvMode = ProtoAddress::IPv4;
  hostMaskLength = 32;
#ifdef SIMULATE
  ipvMode = ProtoAddress::SIM;
#endif //SIMULATE
  
#ifndef SIMULATE
#ifdef UNIX
  handle_mprsel = MPRSELPublishInit(0); // used for sharing mpr info with other processes for forwarding and such
#endif //ifdef UNIX
#endif //SIMULATE
  // hello timer stuff
  Hello_Interval = .5 ; //in seconds
  Hello_Timeout_Factor = 6.0; 
  Hello_Jitter =.5; //% of Hello_Interval

  //TC timer stuff
  TC_Interval=2.0;
  TC_Timeout_Factor=5.0;
  TC_Jitter =.5; //% of TC_Interval 

  //HNA timer stuff
  dohna = true;
  hnaFromFile =  false;
  HNA_Interval=15.0;
  HNA_Timeout_Factor=90;
  HNA_Jitter=.1;

  //set class variables
  D_Hold_Time=15.0; //in seconds

  // init hysteris values
  T_up = .4;
  T_down = .15;
  alpha = .7; //weight given to past 

  noerrors = 1;
  allLinks=false;
  localWillingness = WILL_DEFAULT;
  seqno = 0;
  mssn = 0;

  //init default debug values
  olsrDebugValue = 0;
  SetDebugLevel(olsrDebugValue);

  //create a routing table
  //realRouteTable=ProtoRouteMgr::Create(); // this is now passed to us via SetOlsrRouteTable
  
  //timer stuff
  hello_timer.SetListener(this,&Nrlolsr::OnHelloTimeout);
  hello_jitter_timer.SetListener(this,&Nrlolsr::OnHelloTimeout);
  sendHelloTimerOn=true;

  tc_timer.SetListener(this,&Nrlolsr::OnTcTimeout);
  tc_jitter_timer.SetListener(this,&Nrlolsr::OnTcTimeout);
  sendTcTimerOn=true;

  hna_timer.SetListener(this,&Nrlolsr::OnHnaTimeout);
  hna_jitter_timer.SetListener(this,&Nrlolsr::OnHnaTimeout);
  sendHnaTimerOn=true;
  //DMSG(6,"Exit: Nrlolsr::Nrlolsr()\n");
}

bool 
Nrlolsr::SetOlsrBroadcastAddress(const char* addrname,const char* netmask){
  bool returnvalue = true;
  userDefBroadcast = true;
  returnvalue &= userDefNetBroadAddr.ResolveFromString(addrname);
  userDefBroadMaskLength=atoi(netmask);
  return returnvalue;
}

bool
Nrlolsr::SetOlsrInterfaceAddress(const char* name){
  //DMSG(6,"Enter: Nrlolsr::SetInterfaceAddress(name %s)\n", name);
  strcpy(interfaceName,name);

  interfaceIndex = socket.GetInterfaceIndex(interfaceName);
  socket.GetInterfaceName(interfaceIndex,interfaceName,256);

   //DMSG(6,"Exit: Nrlolsr::SetInterfaceAddress(name %s)\n", name);
  return interfaceIndex > 0;
}
bool
Nrlolsr::SetOlsrIPv4(bool ipv4mode){
  if(ipv4mode){
    ipvMode = ProtoAddress::IPv4;
    hostMaskLength = 32;
  } else {
    ipvMode = ProtoAddress::IPv6;
    hostMaskLength = 128;
  }
  return true;
}   
bool
Nrlolsr::SetOlsrDebugLevel(int debuglvl){
  //DMSG(6,"Enter: Nrlolsr::SetOlsrDebugLevell(debuglvl %d)\n", debuglvl);
  if(debuglvl>=0){
    olsrDebugValue = debuglvl;
    SetDebugLevel(olsrDebugValue);
    //DMSG(6,"Exit: Nrlolsr::SetOlsrDebugLevel(debuglvl %d)\n", debuglvl);
    return true;
  }
//DMSG(6,"Exit: Nrlolsr::SetOlsrDebugLevel(debuglvl %d)\n", debuglvl);
  return false;
}
bool 
Nrlolsr::SetOlsrDebugLog(const char* logfilename){
  //DMSG(6,"Enter: Nrlolsr::SetOlsrDebugLog(logfilename %s)\n", logfilename);
  CloseDebugLog();
  //DMSG(6,"Exit: Nrlolsr::SetOlsrDebugLog(logfilename %s)\n", logfilename);
  return OpenDebugLog(logfilename);
}
bool
Nrlolsr::SetOlsrHelloInterval(double interval){
  //DMSG(6,"Enter: Nrlolsr::SetOlsrHelloInterval(interval %f)\n",interval);
  if(interval>0){
    Hello_Interval = interval;
    Neighb_Hold_Time = Hello_Timeout_Factor*Hello_Interval;     
    Mantissa_Hello_Hold_Interval = doubletomantissa(Neighb_Hold_Time);
    Mantissa_Hello_Interval = doubletomantissa(Hello_Interval);
  } else {
    DMSG(0,"-hi(Hello Interval in seconds) value not positive\n");
    //DMSG(6,"Exit: Nrlolsr::SetOlsrHelloInterval(interval %d)\n",interval);
    return 0;
  }
  //DMSG(6,"Exit: Nrlolsr::SetOlsrHelloInterval(interval %d)\n",interval);
  return 1;
}
bool
Nrlolsr::SetOlsrHelloJitter(double jitter){
  //DMSG(6,"Enter: Nrlolsr::SetOlsrHelloJitter(jitter %f)\n",jitter);
  if(jitter>=0 && jitter < 1) {
    Hello_Jitter = jitter;
  } else {
    DMSG(0,"hj(Hello Jitter in percent of hello interval) value must be <=0 and <1\n");
    //DMSG(6,"Exit: Nrlolsr::SetOlsrHelloJitter(jitter %f)\n",jitter);
    return 0;
  }
  //DMSG(6,"Exit: Nrlolsr::SetOlsrHelloJitter(jitter %f)\n",jitter);
  return 1;
}
bool
Nrlolsr::SetOlsrHelloTimeout(double timeout){
  //DMSG(6,"Enter: Nrlolsr::SetOlsrHelloTimeout(timeout %f)\n",timeout);
  if(timeout > 1){
    Hello_Timeout_Factor = timeout;
    Neighb_Hold_Time = Hello_Timeout_Factor*Hello_Interval;
    Mantissa_Hello_Hold_Interval = doubletomantissa(Neighb_Hold_Time);
  } else {
    DMSG(0,"ht(Hello Timeout factor of hello interval) value only valid if greater than one\n");
    //DMSG(6,"Exit: Nrlolsr::SetOlsrHelloTimeout(timeout %f)\n",timeout);
    return 0;
  }
  //DMSG(6,"Exit: Nrlolsr::SetOlsrHelloTimeout(timeout %f)\n",timeout);
  return 1;
}
bool
Nrlolsr::SetOlsrTCInterval(double interval){
  //DMSG(6,"Enter: Nrlolsr::SetOlsrTCInterval(interval %f)\n",interval);
  if(interval>0){
    TC_Interval = interval;
    Top_Hold_Time = TC_Timeout_Factor*TC_Interval;     
  } else {
    DMSG(0,"-tci(TC Interval in seconds) value not positive\n");
    //DMSG(6,"Exit: Nrlolsr::SetOlsrTCInterval(interval %f)\n",interval);
    return 0;
  }
  //DMSG(6,"Exit: Nrlolsr::SetOlsrTCInterval(interval %f)\n",interval);
  return 1;
}
bool
Nrlolsr::SetOlsrTCJitter(double jitter){
  //DMSG(6,"Enter: Nrlolsr::SetOlsrTCJitter(jitter %f)\n",jitter);
  if(jitter>=0 && jitter < 1) {
    TC_Jitter = jitter;
  } else {
    DMSG(0,"tcj(TC Jitter in percent of TC Interval) value must be <=0 and <1\n");
    //DMSG(6,"Exit: Nrlolsr::SetOlsrTCJitter(jitter %f)\n",jitter);
    return 0;
  }
  //DMSG(6,"Exit: Nrlolsr::SetOlsrTCJitter(jitter %f)\n",jitter);
  return 1;
}
bool
Nrlolsr::SetOlsrTCTimeout(double timeout){
  //DMSG(6,"Enter: Nrlolsr::SetOlsrTCTimeout(timeout %f)\n",timeout);
  if(timeout > 1){
    TC_Timeout_Factor = timeout;
    Top_Hold_Time = TC_Timeout_Factor*TC_Interval;
  } else {
    DMSG(0,"tct(TC Timeout factor of TC Interval) value only valid if greater than one\n");
    //DMSG(6,"Exit: Nrlolsr::SetOlsrTCTimeout(timeout %f)\n",timeout);    
    return 0;
  }
  //DMSG(6,"Exit: Nrlolsr::SetOlsrTCTimeout(timeout %f)\n",timeout);    
  return 1;
}
bool
Nrlolsr::SetOlsrHNAInterval(double interval){
  //DMSG(6,"Enter: Nrlolsr::SetOlsrHNAInterval(interval %f)\n",interval);    
  if(interval>0){
    HNA_Interval = interval;
    HNA_Hold_Time = HNA_Timeout_Factor*HNA_Interval;     
  } else {
    DMSG(0,"-hnai(HNA Interval in seconds) value not positive\n");
    //DMSG(6,"Exit: Nrlolsr::SetOlsrHNAInterval(interval %f)\n",interval);    
    return 0;
  }
  //DMSG(6,"Exit: Nrlolsr::SetOlsrHNAInterval(interval %f)\n",interval);    
  return 1;
}
bool
Nrlolsr::SetOlsrHNAJitter(double jitter){
  //DMSG(6,"Enter: Nrlolsr::SetOlsrHNAJitter(jitter %f)\n",jitter);    
  if(jitter>=0 && jitter < 1) {
    HNA_Jitter = jitter;
  } else {
    DMSG(0,"hnaj(HNA Jitter in percent of HNA Interval) value must be <=0 and <1\n");
    //DMSG(6,"Exit: Nrlolsr::SetOlsrHNAJitter(jitter %f)\n",jitter);    
    return 0;
  }
  //DMSG(6,"Exit: Nrlolsr::SetOlsrHNAJitter(jitter %f)\n",jitter);    
  return 1;
}
bool
Nrlolsr::SetOlsrHNATimeout(double timeout){
  //DMSG(6,"Enter: Nrlolsr::SetOlsrHNATimeout(timeout %f)\n",timeout);    
  if(timeout > 1){
    HNA_Timeout_Factor = timeout;
    HNA_Hold_Time = HNA_Timeout_Factor*HNA_Interval;
  } else {
    DMSG(0,"hnat(HNA Timeout factor of HNA Interval) value only valid if greater than one\n");
    //DMSG(6,"Exit: Nrlolsr::SetOlsrHNATimeout(timeout %f)\n",timeout);    
    return 0;
  }
  //DMSG(6,"Exit: Nrlolsr::SetOlsrHNATimeout(timeout %f)\n",timeout);    
  return 1;
}
bool
Nrlolsr::SetOlsrAllLinks(bool on){
  //DMSG(6,"Enter: Nrlolsr::SetOlsrAllLinks(on %d)\n",on);    
  allLinks = on;
  //DMSG(6,"Exit: Nrlolsr::SetOlsrAllLinks(on %d)\n",on);    
  return true;
}
bool
Nrlolsr::SetOlsrWillingness(int willingness){
  //DMSG(6,"Enter: Nrlolsr::SetOlsrWillingness(willingness %d)\n",willingness);    
  if((willingness > 0) & (willingness < 8)){ 
    localWillingness = willingness;
    //DMSG(6,"Enter: Nrlolsr::SetOlsrWillingness(willingness %d)\n",willingness);    
    return true;
  }
  DMSG(0,"-w(willingness factor) value only valid for integers from 0-7 0 = never 7 = always\n"); 
  //DMSG(6,"Enter: Nrlolsr::SetOlsrWillingness(willingness %d)\n",willingness);    
  return false;
}
bool 
Nrlolsr::SetOlsrHysUp(double up){
  //DMSG(6,"Enter: Nrlolsr::SetOlsrHysUp(up %f)\n",up);    
  if(up>=0 && up<1){
    T_up = up;
  } else {
    DMSG(0,"-hys up value must be >=0 and <1");
    //DMSG(6,"Exit: Nrlolsr::SetOlsrHysUp(up %f)\n",up);    
    return 0;
  }
  //DMSG(6,"Exit: Nrlolsr::SetOlsrHysUp(up %f)\n",up);    
  return 1;
}
bool 
Nrlolsr::SetOlsrHysDown(double down){
  //DMSG(6,"Enter: Nrlolsr::SetOlsrHysDown(down %f)\n",down);    
  if(down>=0 && down<1){
    T_down = down;
  } else {
    DMSG(0,"-hys down value must be >=0 and <1");
    //DMSG(6,"Exit: Nrlolsr::SetOlsrHysDown(down %f)\n",down);    
    return 0;
  }
  //DMSG(6,"Exit: Nrlolsr::SetOlsrHysDown(down %f)\n",down);    
  return 1;
}
bool 
Nrlolsr::SetOlsrHysAlpha(double a){
  //DMSG(6,"Enter: Nrlolsr::SetOlsrHysAlpha(alpha %f)\n",a);    
  if(a>=0 &&  a<1){
    alpha = a;
  } else {
    DMSG(0,"-hys alpha value must be >=0 and <1");
    //DMSG(6,"Exit: Nrlolsr::SetOlsrHysAlpha(alpha %f)\n",a);    
    return 0;
  }
  //DMSG(6,"Exit: Nrlolsr::SetOlsrHysAlpha(alpha %f)\n",a);    
  return 1;
}   
bool 
Nrlolsr::SetOlsrHysOff(bool off){
  //DMSG(6,"Enter: Nrlolsr::SetOlsrHysOff(off %d)\n",off);    
  if(off){
    T_up = .00000001;
    T_down = .00000001;
    alpha = .5;
  } else {
    //6 missing hellos will break link of perfect link
    T_up = .4;
    T_down = .15;
    alpha = .7; //weight given to past
    //2 missing hellos break link of perfect link
    /*    T_up = .8;
    T_down = .3;
    alpha = .5;*/
  }
  //DMSG(6,"Exit: Nrlolsr::SetOlsrHysOff(off %d)\n",off);    
  return 1;
}
bool 
Nrlolsr::SetOlsrHNAOff(bool off){
  //DMSG(6,"Enter: Nrlolsr::SetOlsrHNAOff(off %d)\n",off);    
  if(off){
    dohna = false;
  } else {
    dohna = true;
  }
  //DMSG(6,"Exit: Nrlolsr::SetOlsrHNAOff(off %d)\n",off);    
  return true;
}
bool 
Nrlolsr::SetOlsrHNAFile(const char* filename){
  //DMSG(6,"Enter: Nrlolsr::SetOlsrHNAFile(filename %s)\n",filename);    
  char tag[8], subnetaddress[256], buff[1024];
  int masklength=0;
  ProtoAddress subnetAddress, subnetMask;
  FILE *fid= fopen(filename,"r");
  hnaFromFile = true;
  if(fid){
    //read in hna information
    while(fgets(buff, 1023,fid)){ //parse line   
      sscanf(buff,"%s %s %d",tag,subnetaddress,&masklength);
      if(!strcmp(tag,"HNA")){
	if(subnetAddress.ResolveFromString(subnetaddress)){
	  if(subnetAddress.GetType()==ProtoAddress::IPv4){
	    subnetMask.ResolveFromString("255.255.255.255");
	  } else {
	    subnetMask.ResolveFromString("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
	  }
	  subnetMask.ApplyPrefixMask(masklength);
	  NbrTuple* newhnaroute = new NbrTuple; // yes yes I know lots of wasted space but its only done every once in a while so shut your hole.
	  newhnaroute->N_addr = subnetAddress;
	  newhnaroute->N_2hop_addr = subnetMask;
	  hnaAddresses.QueueObject(newhnaroute);;
	} else {
	  DMSG(0,"Invalid address string %s in %s file\n",subnetaddress,filename);
	  fclose(fid);
	  //DMSG(6,"Exit: Nrlolsr::SetOlsrHNAFile(filename %s)\n",filename);    
	  return 0;
	}
      } else {
	DMSG(0,"invalid option %s in hna setup file %s\n",tag,filename);
	//DMSG(6,"Exit: Nrlolsr::SetOlsrHNAFile(filename %s)\n",filename);
	return 0;
      }
    }
  } else {
    DMSG(0,"-hna %s could not be opened\n",filename);
    //DMSG(6,"Exit: Nrlolsr::SetOlsrHNAFile(filename %s)\n",filename);    
    return 0;
  }
  fclose(fid);
  //DMSG(6,"Exit: Nrlolsr::SetOlsrHNAFile(filename %s)\n",filename);    
  return 1;
}
bool 
Nrlolsr::SetOlsrQos(const char* setQosValue){
  //DMSG(6,"Enter: Nrlolsr::SetOlsrQos(setQosValue %s)\n",setQosValue);    
  qosvalue=atoi(setQosValue);
  //DMSG(6,"Exit: Nrlolsr::SetOlsrQos(setQosValue %s)\n",setQosValue);    
  return true;
}
bool
Nrlolsr::SetOlsrRouteTable(ProtoRouteMgr *theRouteMgr){
  if(theRouteMgr!=NULL){
    realRouteTable = theRouteMgr;
    return true;
  }
  DMSG(0,"Nrlolsr::SetOlsrRouteTable:  theRouteMgr pointer is NULL can not set realRouteTable\n");
  return false;
}

bool
Nrlolsr::Start()
{
  //DMSG(6,"Enter: Nrlolsr::Start()\n");
  //set up timers with correct values.
  Neighb_Hold_Time = Hello_Timeout_Factor*Hello_Interval; 
  Mantissa_Hello_Hold_Interval = doubletomantissa(Neighb_Hold_Time);
  Mantissa_Hello_Interval = doubletomantissa(Hello_Interval);
  Top_Hold_Time=TC_Timeout_Factor*TC_Interval;
  HNA_Hold_Time=HNA_Interval*HNA_Timeout_Factor;
 
  nbr_list.SetHoldTime(Neighb_Hold_Time);         //list of neighbors
  nbr_2hop_list.SetHoldTime(Neighb_Hold_Time);    //list of 2 hop neighbors
  duplicateTable.SetHoldTime(D_Hold_Time);        //list of duplicates default 15 sec
  forwardTable.SetHoldTime(D_Hold_Time);          //list of forwared packets default 15 sec
  topologySet.SetHoldTime(Top_Hold_Time);         //list of topology 
  hnaSet.SetHoldTime(HNA_Hold_Time);              //list of hna associations

  if(userDefBroadcast){
    netBroadAddr=userDefNetBroadAddr;
    broadMaskLength=userDefBroadMaskLength;
  } else if (ipvMode==ProtoAddress::IPv6) {
    netBroadAddr.ResolveFromString("ff05::2");
    broadMaskLength = 128;
  } else if (ipvMode==ProtoAddress::IPv4) {
    netBroadAddr.ResolveFromString("224.0.0.57");
    broadMaskLength = 32; 
#ifdef SIMULATE
  } else if(ipvMode==ProtoAddress::SIM) {
    SIMADDR tempbaddr = 0xffffffff;
    netBroadAddr.SimSetAddress(tempbaddr);
    broadMaskLength = 32;
    DMSG(8,"%s is address\n",netBroadAddr.GetHostString());
#endif //SIMULATE
  }

  netBroadAddr.GetBroadcastAddress(broadMaskLength,broadAddr); 
  broadAddr.SetPort(698);
  // route table and hna stuff
  //realRouteTable->Open();
  initialRouteTable.Init();
  realRouteTable->GetAllRoutes(ipvMode,initialRouteTable);
  if(!hnaFromFile && dohna){ // check to see if hna info set from file
    dohna &= discoverAndSetHNAs(interfaceName);
  } 
  // set local address
  if(!socket.GetInterfaceAddress(interfaceName,ipvMode,myaddress)){
    //if(!ProtoSocket::GetInterfaceAddress(interfaceName,ipvMode,myaddress)){ 
    DMSG(0,"Nrlolsr:: error finding ip address of dev %s\n",interfaceName);
    //DMSG(6,"Exit: Nrlolsr::Start()\n");
    return 0;
  }
  /* broadcast addresses have to be set manually or multicast address used
  //add broadcast address or multicast address  
  if(!netBroadAddr.IsMulticast()){ //add route if not a multicast address
    ProtoAddress gwAddr;
    if(!realRouteTable->SetRoute(netBroadAddr,broadMaskLength,gwAddr,interfaceIndex,-1)){ 
      perror(NULL);
    }
  }
  */
  //install udp socket
  if (!socket.Open(698,ipvMode,false)){
    DMSG(0, "nrlolsr: Erroro opening udp socket! \n");
    //DMSG(6,"Exit: Nrlolsr::Start()\n");
    return false;
  }
  if(qosvalue!=0){
    if(ipvMode==ProtoAddress::IPv4){
      if (!socket.SetTOS(qosvalue)){
	DMSG(0,"nrlolsr: Error setting tos of socket\n");
        //DMSG(6,"Exit: Nrlolsr::Start()\n");
	return false;
      }
    }
#ifdef IPV6
    else {
      if(!socket.SetFlowLabel(qosvalue<<20)){ //shifting bits because IPv6 has different packet format for qos than IPv4
	DMSG(0,"nrlolsr: Error setting flow of socket\n");
        //DMSG(6,"Exit: Nrlolsr::Start\n");
	return false;
      } 
    }
#endif
  }
  if(!socket.Bind(698)){
    DMSG(0,"nrlolsr: Error binding port number 698 to udp socket \n");    
    //DMSG(6,"Exit: Nrlolsr::Start()\n");
    return false;
  }
  if(netBroadAddr.IsMulticast()){ //do multicast stuff
    DMSG(8,"%s is netBroadAddr\n",netBroadAddr.GetHostString());
    if(!socket.JoinGroup(netBroadAddr,interfaceName)){
      DMSG(0,"Nrlolsr: Error joining group %s\n",netBroadAddr.GetHostString());
      //DMSG(6,"Exit: Nrlolsr::Start()\n");
      return false;
    }
    if(!socket.SetMulticastInterface(interfaceName)){
      DMSG(0,"Nrlolsr::Start Error calling SetMulticastInterface with interfaceName=%s\n",interfaceName);
      //DMSG(6,"Exit: Nrlolsr::Start()\n");
      return false;
    }
  } else { //address should be broadcast and will add route later
    if (!socket.SetBroadcast(true)){
      DMSG(0, "Nrlolsr: Error setting broadcast udp socket! \n");
      //DMSG(6,"Exit: Nrlolsr::Start()\n");
      return false;
    }
  }
  //set and install timers
  //hello timer stuff
  hello_timer.SetInterval(Hello_Interval);
  hello_timer.SetRepeat(-1);
  double randValue = UniformRand(Hello_Interval)*Hello_Jitter;
  hello_jitter_timer.SetInterval(randValue);
  hello_jitter_timer.SetRepeat(0);
  //end hello timer stuff

  //tc timer stuff
  tc_timer.SetInterval(TC_Interval);
  tc_timer.SetRepeat(-1);
  randValue = UniformRand(TC_Interval)*TC_Jitter;
  tc_jitter_timer.SetInterval(randValue);
  tc_jitter_timer.SetRepeat(0);
  //end tc timer stuff

  //hna timer stuff
  hna_timer.SetInterval(HNA_Interval);
  hna_timer.SetRepeat(-1);
  randValue = UniformRand(HNA_Interval)*HNA_Jitter;
  hna_jitter_timer.SetInterval(randValue);
  hna_jitter_timer.SetRepeat(0);
  //end hna timer stuff

  //install timers
  if(timerMgrPtr){
    if(!hello_timer.IsActive()) timerMgrPtr->ActivateTimer(hello_timer);
    if(!hello_jitter_timer.IsActive()) timerMgrPtr->ActivateTimer(hello_jitter_timer);
    if(!tc_timer.IsActive()) timerMgrPtr->ActivateTimer(tc_timer);
    if(!tc_jitter_timer.IsActive()) timerMgrPtr->ActivateTimer(tc_jitter_timer);
    if(!hna_timer.IsActive()) timerMgrPtr->ActivateTimer(hna_timer);
    if(!hna_jitter_timer.IsActive()) timerMgrPtr->ActivateTimer(hna_jitter_timer);
  } else {
    DMSG(0,"Nrlolsr::Start() Error timerMgrPtr is NULL!\n");
    return false;
  }
  //DMSG(6,"Exit: Nrlolsr::Start()\n");
  return true;
} // end Nrlolsr::Start(argc %s, argv %d)

bool
Nrlolsr::discoverAndSetHNAs(char* ignoreDev){ // function onwly works with ipv4 in unix
  //DMSG(6,"Enter: Nrlolsr::discoverAndSetHNAs(ignoreDev %s)\n",ignoreDev);
  bool returnvalue = false;
#ifdef UNIX
#ifndef SIMULATE
  if(ipvMode==ProtoAddress::IPv4){ //ipv6 does not yet have auto setup for hna use the file option to set the hna for v6
    char buff[1024],word[256];//currentDev[256];
    ProtoAddress currentMask, currentNetwork;
    FILE *fid = popen("netstat -rn","r");
    fgets(buff,1023,fid);// getting rid of first line
    fgets(buff,1023,fid);// getting rid of first line
    while(fgets(buff, 1023,fid)){ //parse line
      int index=0;
      int wordnumber=0;
      while(isspace(buff[index])) index++; //eat whitespace
      while(buff[index]!='\0'){ // parse word
	wordnumber++;
	sscanf(&buff[index],"%s",word);
	if(wordnumber==1) currentNetwork.ResolveFromString(word);
	if(wordnumber==3) currentMask.ResolveFromString(word);
	if(wordnumber==8) {
	  if(strcmp(word,ignoreDev) && strcmp(word,"lo")){
	    NbrTuple* newhnaroute = new NbrTuple; // yes yes I know lots of wasted space but its only done every once in a while so shut your hole.
	    newhnaroute->N_addr = currentNetwork;
	    newhnaroute->N_2hop_addr = currentMask;
	    hnaAddresses.QueueObject(newhnaroute);
	    returnvalue = true;
	  }
	}
	index+=strlen(word);
	while(isspace(buff[index])) index++; //eat whitespace
      }
    }
    pclose(fid);
  }  else {
    returnvalue = false;
  }
#endif//ifndef SIMULATE
#endif//ifdef UNIX
  //DMSG(6,"Exit: Nrlolsr::discoverAndSetHNAs(ignoreDev %s)\n",ignoreDev);
  return returnvalue;
}

bool 
Nrlolsr::ProcessCommands(int argc, const char*const* argv){
  //DMSG(6,"Enter: Nrlolsr::ProcessCommands(argc,argv)\n");
  bool printusage = false;
  char localinterfacename[256];
  for(int i=1;i<argc;i++){
    if(!strcmp(argv[i],"-b")){
      i++;
      if(!SetOlsrBroadcastAddress(argv[i],argv[i+1])){
	DMSG(0,"Nrlolsr: Error setting broadcast address to:\n          Address: %s netmask %s\n",argv[i],argv[i+1]);
	printusage = true;
      }
      i+=2;
    }
    else if(!strcmp(argv[i],"-ipv6")){
      SetOlsrIPv4(false);
    }
    else if(!strcmp(argv[i],"-ipv4")){
      SetOlsrIPv4(true);
    }
    else if(!strcmp(argv[i],"-i")){
      i++;
      strcpy(localinterfacename,argv[i]);
      if(!SetOlsrInterfaceAddress(localinterfacename)){
	DMSG(0,"error setting InterfaceAddress to %s\n",localinterfacename);
	printusage = true;
      }
    } 
    else if(!strcmp(argv[i],"-d")){
      i++;
      if(!SetOlsrDebugLevel(atoi(argv[i]))){
	DMSG(0,"Nrlolsr: Error setting debug level to %d\n",atoi(argv[i]));
	printusage = true;
      }
    }
    else if(!strcmp(argv[i],"-l")){
      i++;
      if(!SetOlsrDebugLog(argv[i])){
	DMSG(0,"Nrlolsr: Error opening log file %s\n",argv[i]);
	printusage = true;
      }
    }
    else if(!strcmp(argv[i],"-hi")){
      i++;
      if(!SetOlsrHelloInterval(atof(argv[i]))){
	DMSG(0,"Nrlolsr: Error setting Hello Interval to %s\n",argv[i]);
	printusage = true;
      }
    }
    else if(!strcmp(argv[i],"-hj")){
      i++;
      if(!SetOlsrHelloJitter(atof(argv[i]))){
	DMSG(0,"Nrlolsr: Error setting Hello Jitter to %s\n",argv[i]);
	printusage = true;
      }
    }
    else if(!strcmp(argv[i],"-ht")){
      i++;
      if(!SetOlsrHelloTimeout(atof(argv[i]))){
	DMSG(0,"Nrlolsr: Error setting Hello Timeout factor to %s\n",argv[i]);
	printusage = true;
      }
    }
    else if(!strcmp(argv[i],"-tci")){
      i++;
      if(!SetOlsrTCInterval(atof(argv[i]))){
	DMSG(0,"Nrlolsr: Error setting TC Interval to %s\n",argv[i]);
	printusage = true;
      }
    }
    else if(!strcmp(argv[i],"-tcj")){
      i++;
      if(!SetOlsrTCJitter(atof(argv[i]))){
	DMSG(0,"Nrlolsr: Error setting TC Jitter to %s\n",argv[i]);
	printusage = true;
      }
    }
    else if(!strcmp(argv[i],"-tct")){
      i++;
      if(!SetOlsrTCTimeout(atof(argv[i]))){
	DMSG(0,"Nrlolsr: Error setting TC Timeout factor to %s\n",argv[i]);
	printusage = true;
      }
    }
    else if(!strcmp(argv[i],"-hnai")){
      i++;
      if(!SetOlsrHNAInterval(atof(argv[i]))){
	DMSG(0,"Nrlolsr: Error setting HNA Interval to %s\n",argv[i]);
	printusage = true;
      }
    }
    else if(!strcmp(argv[i],"-hnaj")){
      i++;
      if(!SetOlsrHNAJitter(atof(argv[i]))){
	DMSG(0,"Nrlolsr: Error setting HNA Jitter to %s\n",argv[i]);
	printusage = true;
      }
    }
    else if(!strcmp(argv[i],"-hnat")){
      i++;
      if(!SetOlsrHNATimeout(atof(argv[i]))){
	DMSG(0,"Nrlolsr: Error setting HNA Timeout factor to %s\n",argv[i]);
	printusage = true;
      }
    }
    else if(!strcmp(argv[i],"-al")){
      if(!SetOlsrAllLinks(true)){
	DMSG(0,"Nrlolsr: odd Error please send command line text to jdean@itd.nrl.navy.mil\n");
	printusage = true;
      }
    }
    else if(!strcmp(argv[i],"-w")){
      i++;
      if(!SetOlsrWillingness(atoi(argv[i]))){
	DMSG(0,"Nrlolsr: Error setting willingness value to %s\n",argv[i]);
	printusage = true;
      }
    }
    else if(!strcmp(argv[i],"-hys")){
      int j;
      i++;
      if(!strcmp(argv[i],"up")){
	if(!SetOlsrHysUp(atof(argv[i+1]))){
	  DMSG(0,"Nrlolsr: Error %s is invalid -hys up value\n",argv[i+1]);
	  printusage = true;
	}
	j=i+1;
      } 
      else if (!strcmp(argv[i],"down")){
      	if(!SetOlsrHysDown(atof(argv[i+1]))){
	  DMSG(0,"Nrlolsr: Error %s is invalid -hys down value\n",argv[i+1]);
	  printusage = true;
	}
	j=i+1;
      } 
      else if (!strcmp(argv[i],"alpha")){
	if(!SetOlsrHysAlpha(atof(argv[i+1]))){
	  DMSG(0,"Nrlolsr: Error %s is invalid -hys alpha value\n",argv[i+1]);
	  printusage = true;
	}
	j=i+1;
      }
      else if (!strcmp(argv[i],"off")){
	if(!SetOlsrHysOff(true)){
	  DMSG(0,"Nrlolsr: Error that shouldn't ever happen email jdean@itd.nrl.navy.mil with command line\n");
	  printusage = true;
	}
	j=i;
      }
      else if (!strcmp(argv[i],"on")){
	if(!SetOlsrHysOff(false)){
	  DMSG(0,"Nrlolsr: Error that shouldn't ever happen email jdean@itd.nrl.navy.mil with command line\n");
	  printusage = true;
	}
	j=i;
      }
      else {
	DMSG(0,"Nrlolsr: Error %s is invalid -hys option\n",argv[i]);
	printusage = true;
	j=i;
      }
      i=j;
    } 
    else if(!strcmp(argv[i],"-hna")){
      i++;
      if(!strcmp(argv[i],"auto")){
	if(!SetOlsrHNAOff(false)){
	  DMSG(0,"Nrlolsr: Error that should never happen email jdean@itd.nrl.navy.mil with command line\n");
	  printusage = true;
	}
      } 
      else if(!strcmp(argv[i],"off")){
	if(!SetOlsrHNAOff(true)){
	  DMSG(0,"Nrlolsr: Error that should never happen email jdean@itd.nrl.navy.mil with command line\n");
	  printusage = true;
	}
      }
      else {
	if(!SetOlsrHNAFile(argv[i])){
	  DMSG(0,"Nrlolsr: Error opening %s for -hna option\n",argv[i]);
	  printusage = true;
	}
      }
    }
    else if(!strcmp(argv[i],"-qos")){
      i++;
      if(!SetOlsrQos(argv[i])){
	DMSG(0,"Nrlolsr: Error setting qos to value of %s\n",argv[i]);
	printusage = true;
      }
    }
    else if(!strcmp(argv[i],"-v")){	
      DMSG(0,"Nrlolsr::version 7.1\n");
      //DMSG(6,"Exit: Nrlolsr::ProcessCommands(argc,argv)\n");
      return false;
    }
    else {
      printusage = true;
      if(strcmp(argv[i],"-h")){
	DMSG(0,"%s is invalid option\n",argv[i]);
      }
    }
  }
  if(printusage){
    DMSG(0,"this don't make any sents\n");
    DMSG(0,"Nrlolsr:options [-i <interfacename>][-d <debuglvl>][-l <debuglogfile>][-al][-h][-v]\n");
    DMSG(0,"                 [-w <willingness>][-hna auto|<filename>|off][-b <broadaddr> <masklength>]\n");
    DMSG(0,"                 [-hi <HelloInterval>][-hj <HelloJitter>][-ht <HelloTimeoutfactor>]\n");
    DMSG(0,"                 [-tci <TCInterval>][-tcj <TCJitter>][-tct <TCTimeoutfactor>][-ipv6][-ipv4]\n");
    DMSG(0,"                 [-hnai <HNAInterval>][-hnaj <HNAJitter>][-hnat <HNATimeoutfactor>]\n");
    DMSG(0,"                 [-hys up <upvalue> | down <downvalue> | alpha <alphavalue> | on | off]\n");
    DMSG(0,"                 [-qos <qosvalue>]\n\n");
    DMSG(0,"see readme.help for more info\n");
    //DMSG(6,"Exit: Nrlolsr::ProcessCommands(argc,argv)\n");
    return false;
  }
  //DMSG(6,"Exit: Nrlolsr::ProcessCommands(argc,argv)\n");
  return true;
}

bool
Nrlolsr::OnHelloTimeout(ProtoTimer& theTimer)
{
  DMSG(6,"Enter: Nrlolsr::OnHelloTimeout(theTimer)\n");

  //do hello timer stuff
  if(sendHelloTimerOn){
    if(hello_jitter_timer.IsActive()){
      hello_jitter_timer.Deactivate();
    }   
    sendHelloTimerOn=false;
    SendHello();
  } else {
    printCurrentTable(3);
    printTopology(3);
    printRoutingTable(3);
    // do periodic checking here
    // instead of using the packet numbers to see if a packet was lost durring a hello interval to update the historisis
    // I decided thatt it would be easier and more active if it checked for lost packets every hello interval but given the
    // nature of the jitter in the hello interavl the konectivity value for a node is only started to be reduced after 2 of its
    // hello intervals with no recieved message from that node.  the way the jitter is implimented in this code at most 3 hello's 
    // can be recieved in any given interval (and that rarely) so that the one sending hellos faster can fake at most 2 lost
    // hello messages.  if a hello is percieved as no being there a flag is rasied if then the next hello interval there is still 
    // no reply for the missing neighbor its konectivity value is decreased with the factor alpha
    NbrTuple *nb;
    for(nb=nbr_list.PeekInit();nb!=NULL;nb=nbr_list.PeekNext()){
      if(nb!=NULL){
	if(nb->recievedHello>0){
	  DMSG(8,"%s is ",myaddress.GetHostString());
	  DMSG(8,"resetting %s's recieved hello status\n",nb->N_addr.GetHostString());
	  nb->recievedHello=0;
	}
	else if(nb->recievedHello==0) {
	  DMSG(8,"%s ",myaddress.GetHostString());
	  DMSG(8,"did not recieved %s's hello in last window flagging it\n",nb->N_addr.GetHostString());
	  nb->recievedHello=-1;
	}
	else if(nb->recievedHello==-1) {
	  DMSG(8,"%s to ",myaddress.GetHostString());
	  DMSG(8,"%s konectivity %f is reduced; its type is %d\n",nb->N_addr.GetHostString(),nb->konectivity,nb->N_status);
	  nb->konectivity=nb->konectivity*alpha; // reduce value
	}
      }
    }
    //end periodic checking
    
    //set up next timer to send packet out
    sendHelloTimerOn=true;
    double randValue = UniformRand(Hello_Interval)*Hello_Jitter;
    hello_jitter_timer.SetInterval(randValue);
    timerMgrPtr->ActivateTimer(hello_jitter_timer);
  }
  DMSG(6,"Exit: Nrlolsr::OnHelloTimeout(theTimer)\n");
  return true;
} // end Nrlolsr::OnHellotimeout()

bool 
Nrlolsr::SendHello()
{
  DMSG(6,"Enter: %s's Nrlolsr::SendHello() at time %f\n",myaddress.GetHostString(),InlineGetCurrentTime());
  //this method will build and send a hello packet when called it uses methods defined in the olsr_packet_types.h file
  printLinks();
  selectmpr(); //make sure mprs are up to date before building packet
  //DMSG(1,"sending hello packet at time %f\n",InlineGetCurrentTime());
  //DMSG(6,"Enter: SendHello()\n");
  //DMSG(6,"Enter: \n");
  seqno++;  

  //build up parts for adding to hello message
  LinkMessage asymlinks, symlinks, mprlinks, lostlinks;
  asymlinks.linkCode=ASYM_LINKv4;
  asymlinks.reserved=0; 
  
  symlinks.linkCode=SYM_LINKv4;
  symlinks.reserved=0; 

  mprlinks.linkCode=MPR_LINKv4;
  mprlinks.reserved=0; 

  lostlinks.linkCode=LOST_LINKv4;
  lostlinks.reserved=0;

  //actually add the links to their type lists
  NbrTuple *nb;
  for(nb=nbr_list.PeekInit();nb!=NULL;nb=nbr_list.PeekNext()){
    if(nb!=NULL){
      if(nb->N_time>InlineGetCurrentTime()){
	if(nb->N_status==ASYM_LINKv4){
	  asymlinks.addNeighbor(&nb->N_addr);
	}
	if(nb->N_status==SYM_LINKv4){
	  symlinks.addNeighbor(&nb->N_addr); 
	}
	if(nb->N_status==MPR_LINKv4){
	  mprlinks.addNeighbor(&nb->N_addr); 
	}
	if(nb->N_status==LOST_LINKv4){
	  nb->N_status=PENDING_LINK; //move back to pending link type
	  lostlinks.addNeighbor(&nb->N_addr);
	}
      }
    }
  }    
  //  DMSG(4,"size of link messages ASYM=%d | SYM=%d | MPR=%d LOST=%d\n",asymlinks.size,symlinks.size,mprlinks.size,lostlinks.size);

  // build up whole hello message
  HelloMessage hellomessage;
  hellomessage.htime = Mantissa_Hello_Interval; //this value is not currently processed upon being recieved.
  hellomessage.willingness = localWillingness;
  hellomessage.addLinkMessage(&symlinks);
  hellomessage.addLinkMessage(&mprlinks);
  hellomessage.addLinkMessage(&lostlinks);
  hellomessage.addLinkMessage(&asymlinks);
  //DMSG(4,"%d is size of hello message\n",hellomessage.size);

  // build up Olsr message
  OlsrMessage olsrmessage;
  olsrmessage.type=NRLOLSR_HELLO;  
  olsrmessage.Vtime = doubletomantissa(Neighb_Hold_Time);
  olsrmessage.SetO_addr(myaddress);
  olsrmessage.ttl=1;
  olsrmessage.D_seq_num=seqno;
  olsrmessage.setHelloMessage(&hellomessage);
  //  DMSG(4,"%d is size of olsrmessage\n",olsrmessage.size);

  OlsrPacket olsrpacket;
  olsrpacket.addOlsrMessage(&olsrmessage);
  //DMSG(4,"%d is size of packet being sent\n",olsrpacket.size);
  //finished building hello

  // print out hello 
  // HINT: try using ethereal parser for olsr from pf.itd.nrl.navy.mil before using code below
  /*
  int j=0;
  DMSG(1,"*********SENDING HELLO********* at time %f \n",InlineGetCurrentTime());
  for(int i=0;i<buffersize;i++){
    if(i % 4 == 0)
      DMSG(1,"line %d: ",j++);
    DMSG(1,"%02X ",(unsigned char)buffer[i]);
    if(i % 4 == 3)
      DMSG(1,"\n");
  }  
  DMSG(1,"*********HELLO END*********\n");
  */ 
  //end printing

  //sending hello out
  char buffer[1500];
  int buffersize=olsrpacket.pack(buffer,1500);
  unsigned int len = buffersize;
  socket.SetTTL(olsrmessage.ttl+1);
  socket.SendTo(buffer, len, broadAddr);
  //  DMSG(6,"Exit: Nrlolsr::SendHello()\n");
  return true;
}// end Nrlolsr::SendHello()

bool
Nrlolsr::OnTcTimeout(ProtoTimer& theTimer)
{
  //DMSG(6,"Enter: Nrlolsr::OnTcTimeout(theTimer)\n");
  //do tc timer stuff
  if(sendTcTimerOn){
    if(tc_jitter_timer.IsActive()){
      tc_jitter_timer.Deactivate();
    }
    sendTcTimerOn=false;
    SendTc();
  } else {
    sendTcTimerOn=true;
    double randValue = UniformRand(TC_Interval)*TC_Jitter;
    tc_jitter_timer.SetInterval(randValue);
    timerMgrPtr->ActivateTimer(tc_jitter_timer);
  }
  //DMSG(6,"Exit: Nrlolsr::OnTcTimeout(theTimer)\n");
  return true;
} // end Nrlolsr::OnTcTimeout()

bool
Nrlolsr::OnHnaTimeout(ProtoTimer& theTimer)
{
  //DMSG(6,"Enter: Nrlolsr::OnHnaTimeout(theTimer)\n");
  //do hna timer stuff
  if(sendHnaTimerOn){
    if(hna_jitter_timer.IsActive()){
      hna_jitter_timer.Deactivate();
    }    
    sendHnaTimerOn=false;
    SendHna();
  } else {
    sendHnaTimerOn=true;
    printHnaLinks();
    double randValue = UniformRand(HNA_Interval)*HNA_Jitter;
    hna_jitter_timer.SetInterval(randValue);
    timerMgrPtr->ActivateTimer(hna_jitter_timer);
  }
  //DMSG(6,"Exit: Nrlolsr::OnHnaTimeout(theTimer)\n");
  return true;
} // end Nrlolsr::OnHnaTimeout()

bool
Nrlolsr::SendHna(){
  //DMSG(6,"Enter: Nrlolsr::SendHna()\n");
  if(dohna){
    //DMSG(2,"sending thehna \n");
    seqno++;
    NbrTuple* hna;
    HNAMessage hnamessage;
    for(hna=hnaAddresses.PrintPeekInit();hna!=NULL;hna=hnaAddresses.PrintPeekNext()){
      //      DMSG(2,"adding %s with mask ",hna->N_addr.GetHostString());
      //DMSG(2,"%s\n",hna->N_2hop_addr.GetHostString());
      hnamessage.addNetwork(&hna->N_addr,&hna->N_2hop_addr);
    }
    OlsrMessage olsrmessage;
    olsrmessage.type=NRLOLSR_HNA_MESSAGE;
    olsrmessage.Vtime=doubletomantissa(HNA_Hold_Time);
    olsrmessage.SetO_addr(myaddress);
    olsrmessage.ttl=NETWORK_DIAMETER;
    olsrmessage.D_seq_num=seqno;
    olsrmessage.setHNAMessage(&hnamessage);


    OlsrPacket olsrpacket;
    olsrpacket.addOlsrMessage(&olsrmessage);
    char buffer[1500];
    int buffersize=olsrpacket.pack(buffer,1500);
    unsigned int len = buffersize;

    socket.SetTTL(olsrmessage.ttl+1);
    socket.SendTo(buffer, len, broadAddr);
    //DMSG(2,"sent thehna \n");
  }
  //DMSG(6,"Exit: Nrlolsr::SendHna()\n");
  return true;
}
bool 
Nrlolsr::SendTc()
{
  //DMSG(6,"Enter: Nrlolsr::SendTC()\n");
  if((!mprSelectorList.IsEmpty() && !allLinks) || //send tc message with mpr selector set info
     (!nbr_list.IsEmpty() && allLinks)){          //send tc message with full link info
    //DMSG(9,"sending tc from %s at time %f \n",myaddress.GetHostString(),InlineGetCurrentTime());
    seqno++;
    TCMessage tcmessage;
    tcmessage.mssn=mssn;
    tcmessage.reserved=0;
    NbrTuple *nb;
    int numberOfAddr=0;
    // adding the address into the packet to be sent off
    if(!allLinks){ //fill in mpr info
      for(nb=mprSelectorList.PeekInit();nb!=NULL;nb=mprSelectorList.PeekNext()){
	if(nb!=NULL){
	  //DMSG(10,"Adding %s to the tc message\n",nb->N_addr.GetHostString());
	  numberOfAddr++;
	  tcmessage.addMprSelector(&nb->N_addr);
	}
      }
    } else { //fill in full link info
      for(nb=nbr_list.PeekInit();nb!=NULL;nb=nbr_list.PeekNext()){
	if(nb!=NULL){
	  if((nb->N_status==SYM_LINKv4 || nb->N_status==MPR_LINKv4)){ // check to make sure is symetric link
	    //DMSG(10,"%s is the link address\n",nb->N_addr.GetHostString());
	    numberOfAddr++;
	    tcmessage.addMprSelector(&nb->N_addr);
	  }
	}
      }
    }
    // build up Olsr message
    OlsrMessage olsrmessage;
    olsrmessage.type=NRLOLSR_TC_MESSAGE;
    olsrmessage.Vtime=doubletomantissa(Top_Hold_Time);
    olsrmessage.SetO_addr(myaddress);
    olsrmessage.ttl=NETWORK_DIAMETER;
    olsrmessage.D_seq_num=seqno;
    olsrmessage.setTCMessage(&tcmessage);


    OlsrPacket olsrpacket;
    olsrpacket.addOlsrMessage(&olsrmessage);
    char buffer[1500];
    int buffersize=olsrpacket.pack(buffer,1500);

    /* printing tc only use this code after trying to use ethereal parser found at pf.itd.nrl.navy.mil its much easier to use that    
    if(ipvMode==IPv4){
      int j=0;
      DMSG(1,"***********TC MESSAGE***********\n");
      for(int i=0;i<buffersize;i++){
	if(i % 4 == 0)
	  DMSG(1,"line %d: ",j++);
	DMSG(1,"%02X ",(unsigned char)(buffer[i]));
	if(i % 4 == 3)
	  DMSG(1,"\n");
      }  
      DMSG(1,"***********END TC ************\n");
      }*/ //end printing tc

    //finished building tc
    //sending tc out
    unsigned int len = buffersize;
    socket.SetTTL(olsrmessage.ttl+1);
    socket.SendTo(buffer, len, broadAddr);
  }
  //DMSG(6,"Exit: Nrlolsr::SendTC()\n");
  return true;
} // end Nrlolsr::SendTc()

void
Nrlolsr::OnSocketEvent(ProtoSocket &thesocket,ProtoSocket::Event theEvent)
{
  //DMSG(6,"Enter: Nrlolsr::OnSocketEvent(thesocket,theEvent)\n");
  //  printRoutingTable(2);
  switch (theEvent)
    {
    case ProtoSocket::INVALID_EVENT:
      TRACE("ERROR) ...\n");
      break;
    case ProtoSocket::CONNECT:
      TRACE("CONNECT) ...\n");
      break;  
    case ProtoSocket::ACCEPT:
      TRACE("ACCEPT) ...\n");
      break; 
    case ProtoSocket::SEND:
      {
	TRACE("SEND) ...\n");
	break; 
      }
    case ProtoSocket::RECV:
      {
	bool redoroutingtable = false;
	char buffer[1500];
	unsigned int len = 1500;
	ProtoAddress addr;
	if(!thesocket.RecvFrom(buffer, len, addr)){
	  DMSG(0,"OnSocketEvent: error with RecvFrom\n");
	  //  DMSG(6,"Exit: Nrlolsr::OnSocketEvent(thesocket,theEvent)\n");
	  return;
	}
	if((len % 4) != 0){
	  DMSG(0,"Exit: onSocketEvent() invalid packet size %d value \n",len);
	  //DMSG(6,"Exit: Nrlolsr::OnSocketEvent(thesocket,theEvent)\n");
	  return;
	}
	
	// print recieved message yet again please try and use ethereal parser but you can fall back to this code if something is wrong
	/*int j=0;
	  DMSG(1,"***********RECV MESSAGE*********** at time %f from %s \n",InlineGetCurrentTime(),addr.GetHostString());
	  for(int i=0;i<(int)len-1;i++){
	  if(i % 4 == 0)
	  DMSG(1,"line %d: ",j++);
	  DMSG(1,"%02X ",(unsigned char)buffer[i]);
	  if(i % 4 == 3)
	  DMSG(1,"\n");
	  }  
	  DMSG(1,"***********END RECV ************\n");*/
	//end printing recieved message
	OlsrPacket olsrpacket;
	olsrpacket.unpack(buffer,len,ipvMode);
	//cleaning up tables and preparing to parse messages
	nb_purge();
	for_purge();
	dup_purge();
	top_purge();
	hna_purge();
	// go though the messages
	char* littlebuffer;
	int olsrmessagesize = 0;
	while((littlebuffer = (char*)olsrpacket.messages.peekNext(&olsrmessagesize))){
	  OlsrMessage olsrmessage;
	  //DMSG(8,"unpacking  olsrmessage\n");
	  olsrmessage.unpack(littlebuffer,olsrmessagesize,ipvMode);
	  if(IsDuplicate(olsrmessage.O_addr,olsrmessage.D_seq_num)){ // checking to see if message has already been processed.
	    printDuplicateTable(4);
	    //DMSG(7,"recieved duplicate dropping \n");
	  } else { //first time recieving message process it
	    
	    printDuplicateTable(4);
	    addDuplicate(olsrmessage.O_addr,olsrmessage.D_seq_num);
	    int olsrmessageheadersize = 8;
	    
	    if(ipvMode==ProtoAddress::IPv4 || ipvMode==ProtoAddress::SIM)
	      olsrmessageheadersize +=4;
	    else
	      olsrmessageheadersize +=16;
	    
	    if(olsrmessage.type==NRLOLSR_HELLO){
	      DMSG(8,"%s recieving the hello from ",myaddress.GetHostString());
	      DMSG(8,"%s loud and clear at time %f\n",olsrmessage.O_addr.GetHostString(),InlineGetCurrentTime());
	      redoroutingtable = true;
	      //its a hello message parse the interface messages lists
	      //printCurrentTable(3);
	      //process the originator address
	      HelloMessage hellomessage;
	      hellomessage.unpack(olsrmessage.message,olsrmessage.size-olsrmessageheadersize,ipvMode);
	      update_nbr(olsrmessage.O_addr,ASYM_LINKv4,olsrpacket.reserved,olsrmessage.Vtime,hellomessage.willingness);
	      
	      // for printing again use ethereal parser if possible
	      /*
		int buffersize=hellomessage.pack(buffer,1500);
		DMSG(8,"***********RECV HELLO***********\n");
		for(int i=0;i<(int)buffersize;i++){
		if(i % 4 == 0)
		DMSG(8,"line %d: ",j++);
		DMSG(8,"%02X ",(unsigned char)buffer[i]);
		if(i % 4 == 3)
		DMSG(8,"\n");
		}  
		DMSG(8,"***********END HELLO RECV************\n");
	      */
	      //end printing
	      
	      //go though neighbor different link types
	      hellomessage.messages.peekInit();
	      int linkmessagesize=0;
	      while((littlebuffer = (char*)hellomessage.messages.peekNext(&linkmessagesize))){
		LinkMessage linkmessage;
		linkmessage.unpack(littlebuffer,linkmessagesize,ipvMode);
		linkmessage.neighbors.peekInit();
		int neighboraddresssize=0;
		switch(linkmessage.linkCode) {
		case ASYM_LINKv4:
		  //DMSG(8,"in the asymlink area \n");
		  while((littlebuffer = (char*)linkmessage.neighbors.peekNext(&neighboraddresssize))){ //sets littlebuffer to next object size in addresssize
		    //UINT32 neighboraddress = ntohl(((UINT32*)littlebuffer)[0]); 
		    //if(neighboraddress==myaddress.IPv4HostAddr()){
		    ProtoAddress nbr_addr;
		    nbr_addr.SetRawHostAddress(ipvMode,littlebuffer,neighboraddresssize);
		    if(nbr_addr.HostIsEqual(myaddress)){
		      update_nbr(olsrmessage.O_addr,SYM_LINKv4,olsrpacket.reserved);
		    }
		  }
		  //DMSG(8,"returned from update in asym area \n");
		  break;
		case SYM_LINKv4:
		case MPR_LINKv4:
		  //DMSG(8,"in the sym/mpr link area \n");
		  while((littlebuffer = (char*)linkmessage.neighbors.peekNext(&neighboraddresssize))){
		    //	      UINT32 neighboraddress = ntohl(((UINT32*)littlebuffer)[0]); 
		    ProtoAddress nbr_addr;
		    nbr_addr.SetRawHostAddress(ipvMode,littlebuffer,neighboraddresssize);
		    //DMSG(9,"in while loop of sym/mpr link area %s ",nbr_addr.GetHostString());
		    //DMSG(9,"<- is %s's nbr address\n",olsrmessage.O_addr.GetHostString());
		    
		    if(nbr_addr.HostIsEqual(myaddress)){	      //if(neighboraddress==myaddress.IPv4HostAddr()){
		      update_mprselector(olsrmessage.O_addr,linkmessage.linkCode); //add/remove from mpr selector set depending on type
		      update_nbr(olsrmessage.O_addr,SYM_LINKv4,olsrpacket.reserved); // will update the time this doesn't mean its not an mpr
		    } else {
		      //DMSG(9,"updating 2 hop neighbor table\n");
		      update_2hop_nbr(olsrmessage.O_addr,nbr_addr);
		    }
		  }
		  //DMSG(8,"returned from update in sym/mpr \n");
		  break;
		case LOST_LINKv4:
		  //DMSG(8,"in the lostlink area \n");
		  while((littlebuffer = (char*)linkmessage.neighbors.peekNext(&neighboraddresssize))){
		    //UINT32 neighboraddress = ntohl(((UINT32*)littlebuffer)[0]);
		    ProtoAddress nbr_addr;
		    nbr_addr.SetRawHostAddress(ipvMode,littlebuffer,neighboraddresssize);
		    //DMSG(9,"in while loop of lost link area %s <= is ",nbr_addr.GetHostString());
		    //DMSG(9,"%s's nbr address\n",olsrmessage.O_addr.GetHostString());
		    if(nbr_addr.HostIsEqual(myaddress)){  // if(neighboraddress==myaddress.IPv4HostAddr()){
		      //make asym link and lose all of its 2 hop neighbors
		      update_nbr(olsrmessage.O_addr,LOST_LINKv4,olsrpacket.reserved);
		    } else {
		      remove_2hop_link(olsrmessage.O_addr,nbr_addr);
		    }
		  }
		  //DMSG(8,"returned from updating in lost area \n");
		  break;
		}
	      }
	      //	DMSG(8,"finished parsing hello message\n");
	      //printCurrentTable(3); 
	    } else if(olsrmessage.type==NRLOLSR_TC_MESSAGE) {
	      //DMSG(8,"%s recieving the tc from ",myaddress.GetHostString());
	      //DMSG(8,"%s loud and clear\n",olsrmessage.O_addr.GetHostString());
	      redoroutingtable = true;
	      //printTopology(3);
	      TCMessage tc;
	      tc.unpack(olsrmessage.message,olsrmessage.size-olsrmessageheadersize,ipvMode);
	      if(updateTopology(olsrmessage.O_addr,tc.mssn)){  // check to see if mssn is most current
		int mprselectorsize=0; //not really used but holds value of size of object returned
		tc.mprselectors.peekInit();
		while((littlebuffer = (char*)tc.mprselectors.peekNext(&mprselectorsize))){
		  ProtoAddress nbr_addr;
		  nbr_addr.SetRawHostAddress(ipvMode,littlebuffer,mprselectorsize);	   
		  //DMSG(9,"in while of tc %s",nbr_addr.GetHostString());
		  //DMSG(9,"<- is mprselector address of %s",olsrmessage.O_addr.GetHostString());
		  //DMSG(9," %s <- is my address\n",myaddress.GetHostString());
		  addTopologyInfo(olsrmessage.O_addr,nbr_addr,tc.mssn,tc.reserved,olsrmessage.Vtime);
		}
		// update tables and then forward tc message if it was sent by a node that selected this node as its mpr
		//printTopology(3);
		//will check for to see if should forward packet later in this function and forward if needed
	      } 
	    } else if(olsrmessage.type==NRLOLSR_HNA_MESSAGE) {
	      int hnasize=0; //not really used but holds value of size of object returned
	      HNAMessage hna;
	      hna.unpack(olsrmessage.message,olsrmessage.size-olsrmessageheadersize,ipvMode);
	      ProtoAddress hna_addr,hna_mask;
	      bool addrturn = true;
	      hna.networksandmasks.peekInit();
	      //DMSG(4,"size of hna message %s\n",hna.size)
#ifdef UNIX
		  if(olsrDebugValue>=2){ //this if block prints out all hna info of a neighbor as they get parsed.  going to be used by cmap for display
			FILE *fid = popen("date -u +%T","r");
			char dateBuffer[10];
			fgets(dateBuffer,9,fid);
			pclose(fid);
			fprintf(stdout,"Hna-Networks List for %s: %s.%06d\n",olsrmessage.O_addr.GetHostString(),dateBuffer,GetLittleTime());
		  }
#endif //UNIX	      
	      while((littlebuffer = (char*)hna.networksandmasks.peekNext(&hnasize))){
		if(addrturn) {
		  hna_addr.SetRawHostAddress(ipvMode,littlebuffer,hnasize);
		} else {
		  hna_mask.SetRawHostAddress(ipvMode,littlebuffer,hnasize);
		  addHnaInfo(olsrmessage.O_addr,hna_addr,hna_mask,olsrmessage.Vtime);
		  if(olsrDebugValue>=2){
		    fprintf(stdout,"%s -> ",olsrmessage.O_addr.GetHostString());//fixme
		    fprintf(stdout,"%s/%d\n",hna_addr.GetHostString(),hna_mask.GetPrefixLength());
		  }
		}
		addrturn=!addrturn;
	      }
	      if(olsrDebugValue>=2){
		fprintf(stdout,"End of Hna-Networks List for %s\n",olsrmessage.O_addr.GetHostString());
		fflush(stdout);	  
	      }
	      // moved forwarding out of processing area so forwarding is checked after each message is fully processed or ignored
	    }
	  } //finshed processing message check for forwarding
	  //if(!WasForwarded(olsrmessage.O_addr,olsrmessage.D_seq_num) && !mprSelectorList.IsEmpty()){ //message hasn't been forwared yet and I am mpr
	  if(!WasForwarded(olsrmessage.O_addr,olsrmessage.D_seq_num) && (NULL!=mprSelectorList.FindObject(addr))){ //message hasn't been forwared yet and I am mpr
	    if(olsrmessage.ttl!=0 && olsrmessage.type==NRLOLSR_TC_MESSAGE || olsrmessage.type==NRLOLSR_HNA_MESSAGE){
	      //DMSG(7,"%s forwarding message",myaddress.GetHostString());
	      addForwarded(olsrmessage.O_addr,olsrmessage.D_seq_num);
	      olsrmessage.ttl--;
	      olsrmessage.hopc++;
	      OlsrPacket olsrpacket2forward;
	      olsrpacket2forward.addOlsrMessage(&olsrmessage);
	      char forwardbuffer[1500];
	      int forwardbuffersize=olsrpacket2forward.pack(forwardbuffer,1500);
	      unsigned int forwardlen = forwardbuffersize;
	      thesocket.SetTTL(olsrmessage.ttl+1);
	      thesocket.SendTo(forwardbuffer, forwardlen, broadAddr);
	    }
	  }
	}
	//printRoutingTable(3);
	redoroutingtable = true; // theres a problem currently with timed out neighbors not setting flag.
	if(redoroutingtable) {
	  makeNewRoutingTable();
	  addHnaRoutes();
	  //printRoutingTable(3);
	}
	//DMSG(6,"Exit: Nrlolsr::OnSocketEvent(thesocket,theEvent)\n");
	return;
      }
    case ProtoSocket::DISCONNECT:
      TRACE("DISCONNECT) ...\n");
      break;  
    }
  //DMSG(6,"Exit: Nrlolsr::OnSocketEvent(thesocket,theEvent)\n");
  return;
}//end Nrlolsr::OnSocketEvent(thesocket,theEvent)}

int
Nrlolsr::update_nbr(ProtoAddress id,int status,UINT16 delayValue) {
  //DMSG(6,"Enter: Nrlolsr::update_nbr(id %s,status %d,delayValue %d)\n",id.GetHostString(),status,delayValue);
  NbrTuple *tuple_pt, *children, *parents;
  int updateMprs=0;
  tuple_pt = nbr_list.FindObject(id);
  switch(status) {
    case ASYM_LINKv4: 
      DMSG(0,"error in Nrlolsr::update_nbr(short call function) in ASYM_LINKv4 area should never happen\n");
      break;
  case SYM_LINKv4:  // can be mpr link as well 
    if(tuple_pt) { //should always pass if done correctly
      // update link time
      if(tuple_pt->N_status==ASYM_LINKv4){
	tuple_pt->hop=1;
	tuple_pt->N_status=SYM_LINKv4;
	//link up known children
	for(children=(tuple_pt->children).PeekInit();children!=NULL;children=(tuple_pt->children).PeekNext()){
	  if(children!=NULL){
	    if((children->stepparents).FindObject(tuple_pt->N_addr)){ //remove stepparent status
	      (children->stepparents).RemoveCurrent();
	    } else {
	      DMSG(0,"didn't find stepparents in SYM_LINKv4 area!!!  updated node %s with child ",tuple_pt->N_addr.GetHostString());
	      DMSG(0,"%s who doesn't know about ",children->N_addr.GetHostString());
	      DMSG(0,"%s\n",tuple_pt->N_addr.GetHostString());
	    }
	    (children->parents).QueueObject(tuple_pt); // link the child to parent node
	    if(nbr_2hop_list.FindObject(children->N_addr)){//need to take out if its there already to update time
	      nbr_2hop_list.RemoveCurrent(); 
	    } else {
	      // is okay cause could have been only a 1 hop neighbor
	    }
	    nbr_2hop_list.QueueObject(children); // add to two hop list 
	  }
	}	    
	updateMprs=1;
      }
      //DMSG(7,"Moving %s to the sym neighbor table \n",id.GetHostString());
      nbr_list.RemoveCurrent();
      tuple_pt->N_time=InlineGetCurrentTime() + Neighb_Hold_Time;
      tuple_pt->N_delay=delayValue;
      nbr_list.QueueObjectAddressSort(tuple_pt); //sorts neighbors by address to avoid route flapping
      //checkCurrentTable(2);      
    } else {
      DMSG(0,"Error: didn't pass for some reason Nrlolsr::nbr_update,sym_link");}
    break;
  case LOST_LINKv4:  //recieved a lost link from a neighbor you can still hear
    if(tuple_pt) { //should always pass
      //DMSG(7,"changing nb %s to asym list at time %f \n",tuple_pt->N_addr.GetHostString(),InlineGetCurrentTime());
      // check and remove nodes children
      nbr_list.RemoveCurrent();
      for(children=(tuple_pt->children).PeekInit();children!=NULL;children=(tuple_pt->children).PeekNext()){
	if(children!=NULL){
	  //abandon children
	  if((children->parents).FindObject(tuple_pt->N_addr))
	    (children->parents).RemoveCurrent();
	  else if((children->stepparents).FindObject(tuple_pt->N_addr))
	    (children->stepparents).RemoveCurrent();
	  if((children->parents).IsEmpty()){
	    //child lost last parent, child runs free	      
	    //DMSG(7,"removing 2 hop %s ",children->N_addr.GetHostString());
	    //DMSG(7,"cause %s deleated (lost link)\n",tuple_pt->N_addr.GetHostString());
	    fflush(stdout);
	    nbr_2hop_list.FindObject(children->N_addr);
	    nbr_2hop_list.RemoveCurrent();
	    if(!nbr_list.FindObject(children->N_addr)){ //check to see if it was exclusivly a 2 hop neighbor
	      //get rid of step children
	      for(parents=(children->children).PeekInit();parents!=NULL;parents=(children->children).PeekNext()){
		if(parents!=NULL){
		  if((parents->stepparents).FindObject(children->N_addr)){
		    (parents->stepparents).RemoveCurrent();
		  } else {
		    //error statements shouldn't enter here
		    if((parents->parents).FindObject(children->N_addr)){
		      DMSG(0,"missing stepparents link for node %s to stepparent ",parents->N_addr.GetHostString());
		      DMSG(0,"%s in LOST_LINKv4 area:\n",children->N_addr.GetHostString());
		      DMSG(0,"did find parent link! wasn't moved to stepparent correctly someplace in past!\n");
		    } else {
		      DMSG(0,"missing stepparents link for node %s to stepparents ",parents->N_addr.GetHostString());
		      DMSG(0,"%s in LOST_LINKv4 area: no parent link found\n",children->N_addr.GetHostString());
		    }
		    //end error stantments 
		  }
		}
	      }
	      (children->children).Clear();
	      //get rid of step parents
	      for(parents=(children->stepparents).PeekInit();parents!=NULL;parents=(children->stepparents).PeekNext()){
		if(parents!=NULL){
		  //if(parents->N_addr.IPv4HostAddr()!=tuple_pt->N_addr.IPv4HostAddr()){
		  if(!parents->N_addr.HostIsEqual(tuple_pt->N_addr)){
		    if((parents->children).FindObject(children->N_addr)){
		      (parents->children).RemoveCurrent();
		    } else {
		      DMSG(0,"missing childlink for node %s to child ",parents->N_addr.GetHostString());
		      DMSG(0,"%s in LOST_LINKv4 area: ",children->N_addr.GetHostString());
		      DMSG(0,"%s stepparents was ",children->N_addr.GetHostString());
		      DMSG(0,"%s\n",parents->N_addr.GetHostString());
		    }
		  }
		}
	      }
	      (children->stepparents).Clear();
	      
	      //	    if(children->hop==2){
	      //DMSG(10,"freeing it \n");
	      delete children;
	      //free(children);
	    } 
	  }
	}
      }
      (tuple_pt->children).Clear();
      NbrTuple *mprtuple;
      if((mprtuple = mprSelectorList.FindObject(tuple_pt->N_addr))){
	mprSelectorList.RemoveCurrent();
	delete mprtuple;
	//free(mprtuple);
	updateSM();
      }
      //update current node
      if((tuple_pt->parents).IsEmpty()){ // has no parents can remain a 1 hop
	tuple_pt->hop=1;
      }
      else
	tuple_pt->hop=2;             // is now a 2 hop neighbor
      tuple_pt->N_time=InlineGetCurrentTime() + Neighb_Hold_Time;
      tuple_pt->N_status=ASYM_LINKv4;
      tuple_pt->N_delay=delayValue;
      nbr_list.QueueObjectAddressSort(tuple_pt);
      //nbr_list.QueueObject(tuple_pt);
    }
  }
  //DMSG(6,"Exit: Nrlolsr::update_nbr(id %s,status %d,delayValue %d)\n",id.GetHostString(),status,delayValue);
  return 1;
}

int
Nrlolsr::update_nbr(ProtoAddress id,int status,UINT16 delayValue, UINT8 Vtime, UINT8 willingness) {
  //DMSG(6,"Enter: Nrlolsr::update_nbr(id %s,status %d,delayValue %d)\n",id.GetHostString(),status,delayValue);
  NbrTuple *tuple_pt, *children, *parents;
  int updateMprs=0;
  tuple_pt = nbr_list.FindObject(id);
  if(tuple_pt==NULL){
    //DMSG(8," neighbor %s not found in list\n",id.GetHostString());
  }
  switch(status) {
  case ASYM_LINKv4:
    //if(id.IPv4HostAddr()!=myaddress.IPv4HostAddr()) { // shouldn't ever happen
    if(!id.HostIsEqual(myaddress)){ // shouldn't ever happen
      if(tuple_pt) {
	//if(tuple_pt->N_status!=SYM_LINKv4){
	  //if link is asym then update the object and move it to the back keeping asym status
	  //DMSG(8,"in asylink areas \n");
	  nbr_list.RemoveCurrent();
	  //printCurrentTable(3);
	  DMSG(8,"hello message reieved konectivity %f is improving\n",tuple_pt->konectivity);
	  tuple_pt->konectivity=alpha*tuple_pt->konectivity+(1-alpha);
	  if(tuple_pt->konectivity>T_up && tuple_pt->N_status==PENDING_LINK){
	    tuple_pt->N_status=ASYM_LINKv4;
	  }
	  tuple_pt->N_time=InlineGetCurrentTime() + mantissatodouble(Vtime); 
	  tuple_pt->N_willingness = willingness;
	  tuple_pt->N_delay=delayValue;
	  nbr_list.QueueObjectAddressSort(tuple_pt);
	  //nbr_list.QueueObject(tuple_pt);
	  //DMSG(7,"refreshed one hop neighbor with timeout time %f\n",tuple_pt->N_time);
	  //}
      }
      else {
	// check to see if its a two hop neighbor
	tuple_pt = nbr_2hop_list.FindObject(id);
	if(tuple_pt) {
	  //set queue up for being one hop neighbor (handling timeouts of children)
	  tuple_pt->SetHoldTime(mantissatodouble(Vtime));
	  //add to 1 hop list but don't erase 2 hop list entry
	  tuple_pt->N_time=InlineGetCurrentTime() + mantissatodouble(Vtime);
	  tuple_pt->konectivity=(1-alpha); //set initial konectivity value
	  DMSG(8,"hello message reieved from known 2 hop neighbor setting konectivity to %f\n",tuple_pt->konectivity);
	  if(tuple_pt->konectivity>T_up){
	    tuple_pt->N_status=ASYM_LINKv4;
	    //tuple_pt->hop=1; //don't make it a one hop neighbor till its sym
	  } else {
	    //DMSG(7,"Adding %s nbr to pending \n",tuple_pt->N_addr.GetHostString());
	    tuple_pt->N_status=PENDING_LINK;
	  }
	  tuple_pt->N_delay=delayValue;
	  tuple_pt->N_willingness = willingness;
	  nbr_list.QueueObjectAddressSort(tuple_pt);
	  //nbr_list.QueueObject(tuple_pt);
	}
	else {
	  //DMSG(2,"Adding %s asym neighbor table \n",id.GetHostString());
	  //not in current table add new tuple
	  tuple_pt = new NbrTuple;
	  tuple_pt->SetHoldTime(mantissatodouble(Vtime)); //set the queue up for the Vtime value
	  tuple_pt->N_addr=id;
	  tuple_pt->konectivity=(1-alpha); //set initial konectivity value
	  DMSG(8,"hello message reieved from new neighbor setting konectivity to %f\n",tuple_pt->konectivity);
	  if(tuple_pt->konectivity>T_up){
	    tuple_pt->N_status=ASYM_LINKv4;
	    tuple_pt->hop=1; //ok to do this here cause its a new neighbor
	  } else {
	    tuple_pt->N_status=PENDING_LINK;
	    tuple_pt->hop=1;  //ok to do this here cause its a new neighbor
	  }
	  tuple_pt->N_time=InlineGetCurrentTime() + Neighb_Hold_Time;
	  tuple_pt->N_delay=delayValue;
	  tuple_pt->N_willingness = willingness;
	  nbr_list.QueueObjectAddressSort(tuple_pt);
	  //nbr_list.QueueObject(tuple_pt);
	}
      }
    }
    tuple_pt->recievedHello=1; //used for historisis
    if(tuple_pt->N_status==PENDING_LINK){
      //DMSG(6,"Exit: Nrlolsr::update_nbr(id %s,status %d,delayValue %d)\n",id.GetHostString(),status,delayValue);
      return 0;
    } else {
      //DMSG(6,"Exit: Nrlolsr::update_nbr(id %s,status %d,delayValue %d)\n",id.GetHostString(),status,delayValue);
      return 1;
    }
    break;
  case SYM_LINKv4:  // can be mpr link as well 
    if(tuple_pt) { //should always pass if done correctly
      // update link time
      if(tuple_pt->N_status==ASYM_LINKv4){
	tuple_pt->hop=1;
	tuple_pt->N_status=SYM_LINKv4;
	//link up known children
	for(children=(tuple_pt->children).PeekInit();children!=NULL;children=(tuple_pt->children).PeekNext()){
	  if(children!=NULL){
	    if((children->stepparents).FindObject(tuple_pt->N_addr)){ //remove stepparent status
	      (children->stepparents).RemoveCurrent();
	    } else {
	      DMSG(0,"didn't find stepparents in SYM_LINKv4 area!!!  updated node %s with child ",tuple_pt->N_addr.GetHostString());
	      DMSG(0,"%s who doesn't know about ",children->N_addr.GetHostString());
	      DMSG(0,"%s\n",tuple_pt->N_addr.GetHostString());
	    }
	    (children->parents).QueueObject(tuple_pt); // link the child to parent node
	    if(nbr_2hop_list.FindObject(children->N_addr)){//need to take out if its there already to update time
	      nbr_2hop_list.RemoveCurrent(); 
	    } else {
	      // is okay cause could have been only a 1 hop neighbor
	    }
	    nbr_2hop_list.QueueObject(children); // add to two hop list 
	  }
	}	    
	updateMprs=1;
      }
      //DMSG(7,"Moving %s to the sym neighbor table \n",id.GetHostString());
      nbr_list.RemoveCurrent();
      tuple_pt->N_time=InlineGetCurrentTime() + Neighb_Hold_Time;
      tuple_pt->N_delay=delayValue;
      tuple_pt->N_willingness = willingness;
      nbr_list.QueueObjectAddressSort(tuple_pt);
      //nbr_list.QueueObject(tuple_pt);
      //checkCurrentTable(2);
      
      //this call is made only in send hello
      //if(updateMprs)
      //	selectmpr();
    }
    else {
      DMSG(0,"didn't pass for some reason nrouter/nbr_update,sym_link");}
    break;
  case LOST_LINKv4:  //recieved a lost link from a neighbor you can still hear
    if(tuple_pt) { //should always pass
      //DMSG(7,"changing nb %s to asym list at time %f \n",tuple_pt->N_addr.GetHostString(),InlineGetCurrentTime());
      // check and remove nodes children
      nbr_list.RemoveCurrent();
      for(children=(tuple_pt->children).PeekInit();children!=NULL;children=(tuple_pt->children).PeekNext()){
	if(children!=NULL){
	  //abandon children
	  if((children->parents).FindObject(tuple_pt->N_addr))
	    (children->parents).RemoveCurrent();
	  else if((children->stepparents).FindObject(tuple_pt->N_addr))
	    (children->stepparents).RemoveCurrent();
	  if((children->parents).IsEmpty()){
	    //child lost last parent, child runs free	      
	    //DMSG(7,"removing 2 hop %s ",children->N_addr.GetHostString());
	    //DMSG(7,"cause %s deleated (lost link)\n",tuple_pt->N_addr.GetHostString());
	    fflush(stdout);
	    nbr_2hop_list.FindObject(children->N_addr);
	    nbr_2hop_list.RemoveCurrent();
	    if(!nbr_list.FindObject(children->N_addr)){ //check to see if it was exclusivly a 2 hop neighbor
	      //get rid of step children
	      for(parents=(children->children).PeekInit();parents!=NULL;parents=(children->children).PeekNext()){
		if(parents!=NULL){
		  if((parents->stepparents).FindObject(children->N_addr)){
		    (parents->stepparents).RemoveCurrent();
		  } else {
		    //error statements shouldn't enter here
		    if((parents->parents).FindObject(children->N_addr)){
		      DMSG(0,"missing stepparents link for node %s to stepparent ",parents->N_addr.GetHostString());
		      DMSG(0,"%s in LOST_LINKv4 area: /n",children->N_addr.GetHostString());
		      DMSG(0,"but did find parent link! wasn't moved to stepparent correctly someplace in past!");
		    } else {
		      DMSG(0,"missing stepparents link for node %s to stepparent ",parents->N_addr.GetHostString());
		      DMSG(0,"%s in LOST_LINKv4 area: no parent link found",children->N_addr.GetHostString());
		    }
		    //end error stantments 
		  }
		}
	      }
	      (children->children).Clear();
	      //get rid of step parents
	      for(parents=(children->stepparents).PeekInit();parents!=NULL;parents=(children->stepparents).PeekNext()){
		if(parents!=NULL){
		  //if(parents->N_addr.IPv4HostAddr()!=tuple_pt->N_addr.IPv4HostAddr()){
		  if(!parents->N_addr.HostIsEqual(tuple_pt->N_addr)){
		    if((parents->children).FindObject(children->N_addr)){
		      (parents->children).RemoveCurrent();
		    } else {
		      DMSG(0,"missing childlink for node %s to child ",parents->N_addr.GetHostString());
		      DMSG(0,"%s in LOST_LINKv4 area: ",children->N_addr.GetHostString());
		      DMSG(0,"%s stepparent was ",children->N_addr.GetHostString());
		      DMSG(0,"%s\n",parents->N_addr.GetHostString());
		    }
		  }
		}
	      }
	      (children->stepparents).Clear();
	      delete children;
	      //free(children);
	    } 
	  }
	}
      }
      (tuple_pt->children).Clear();
      NbrTuple *mprtuple;
      if((mprtuple = mprSelectorList.FindObject(tuple_pt->N_addr))){
	mprSelectorList.RemoveCurrent();
	delete mprtuple;
	//free(mprtuple);
	updateSM();
      }
      //update current node
      if((tuple_pt->parents).IsEmpty()){ // has no parents can remain a 1 hop
	tuple_pt->hop=1;
      }
      else
	tuple_pt->hop=2;             // is now a 2 hop neighbor
      tuple_pt->N_time=InlineGetCurrentTime() + Neighb_Hold_Time;
      tuple_pt->N_status=ASYM_LINKv4;
      tuple_pt->N_delay=delayValue;
      tuple_pt->N_willingness = willingness;
      nbr_list.QueueObjectAddressSort(tuple_pt);
      //nbr_list.QueueObject(tuple_pt);
    }
  }
  //DMSG(6,"Exit: Nrlolsr::update_nbr(id %s,status %d,delayValue %d)\n",id.GetHostString(),status,delayValue);
  return 1;
}

void 
Nrlolsr::update_2hop_nbr(ProtoAddress onehop_addr,ProtoAddress twohop_addr){
  //DMSG(6,"Enter: Nrlolsr::update_2hop_nbr(onehop %s,twohop",onehop_addr.GetHostString());
  //DMSG(6," %s\n",twohop_addr.GetHostString());
  
  NbrTuple *tuple_pt,*parent_tuple_pt,*other_tuple_pt;
  int updateMprs=0;
  int parentcheck=0;
  int errortype=0;
  parent_tuple_pt=nbr_list.FindObject(onehop_addr);
  parentcheck=parent_tuple_pt->N_status==MPR_LINKv4 || parent_tuple_pt->N_status==SYM_LINKv4;
  //printCurrentTable(3);
  //DMSG(10,"parent check %d \n",parentcheck);
  
  if((tuple_pt=nbr_2hop_list.FindObject(onehop_addr,twohop_addr))){ //returns two hop guy
    if(parentcheck){
      //DMSG(8,"found in correct link \n");
      fflush(stdout);
      //update time 
      if((parent_tuple_pt=(tuple_pt->parents).FindObject(onehop_addr))){ 
	//	if(parent_tuple_pt=(tuple_pt->stepparents).FindObject(onehop_addr))
	//  DMSG(0,"both step parent and parent present how did it get this way?");
	errortype=4;
	//DMSG(9,"real child \n",parent_tuple_pt);
	(tuple_pt->parents).RemoveCurrent(); // removes the pointer pointing to the parent so it can be updated
	//printCurrentTable(3);
	(tuple_pt->parents).QueueObject(parent_tuple_pt); 
	//printCurrentTable(3);
	nbr_2hop_list.RemoveCurrent();
	nbr_2hop_list.QueueObject(tuple_pt);
      }
      else {
	// was a step child check to see if neighbor is true one hop
	errortype=5;
	parent_tuple_pt=(tuple_pt->stepparents).FindObject(onehop_addr);
	//DMSG(9,"step child \n");
	(tuple_pt->stepparents).RemoveCurrent(); // removes the pointer pointing to the parent so it can be updated
	if(parent_tuple_pt->N_status==MPR_LINKv4 || parent_tuple_pt->N_status==SYM_LINKv4) {
	  updateMprs=1;
	  (tuple_pt->parents).QueueObject(parent_tuple_pt);
	  nbr_2hop_list.RemoveCurrent();
	  nbr_2hop_list.QueueObject(tuple_pt);
	}
	else {
	  (tuple_pt->stepparents).QueueObject(parent_tuple_pt);
	}
      }
      other_tuple_pt=(parent_tuple_pt->children).FindObject(twohop_addr);
      //DMSG(11,"%p %p should be the same \n",tuple_pt,other_tuple_pt);
      fflush(stdout);
      (parent_tuple_pt->children).RemoveCurrent(); // removes the pointer pointing to the child so it can be updated
      (parent_tuple_pt->children).QueueObject(other_tuple_pt);  // updating the time again
    }
  }
  else if((tuple_pt=nbr_2hop_list.FindObject(twohop_addr))){
    //is already someones two hop neighbor just link them together
    //DMSG(8,"is an existing 2 hop neighbor \n");
    if(parent_tuple_pt->N_status==MPR_LINKv4 || parent_tuple_pt->N_status==SYM_LINKv4) { //make sure neighbor is true one hop
      errortype=6;
      updateMprs=1;
      (tuple_pt->parents).QueueObject(parent_tuple_pt); // link child to parent node   
      nbr_2hop_list.RemoveCurrent();  // next two lines update the timeout value of the 2 hop neighbor
      nbr_2hop_list.QueueObject(tuple_pt);
    } else {
      errortype=7;
      (tuple_pt->stepparents).QueueObject(parent_tuple_pt); //link child to node which isn't a real one hop node yet
    }
    (parent_tuple_pt->children).QueueObject(tuple_pt); // link parent to child node    
  } 
  else if((tuple_pt=nbr_list.FindObject(twohop_addr))){
    //is already a one hop neighbor just link them together
    //DMSG(8,"is an existing 1 hop neighbor \n");    
    //DMSG(8,"parent_tuple_pt->N_status=%d mpr=%d sym=%d\n",parent_tuple_pt->N_status,MPR_LINKv4,SYM_LINKv4);
    if(parent_tuple_pt->N_status==MPR_LINKv4 || parent_tuple_pt->N_status==SYM_LINKv4) { //make sure neighbor is true one hop
      errortype=8;
      updateMprs=1;
      (tuple_pt->parents).QueueObject(parent_tuple_pt); // link the child to parent node
      //DMSG(7,"Adding 2hop neighbor %s to ",parent_tuple_pt->N_addr.GetHostString()); 
      //DMSG(7,"%s to neighbor table now\n",tuple_pt->N_addr.GetHostString());
      nbr_2hop_list.QueueObject(tuple_pt); // add to two hop list 
      (parent_tuple_pt->children).QueueObject(tuple_pt); // link the parent to the child node
    } else {
      //do nothing not a real neighbor yet
      errortype=9;
    }
  } 
  else {
    //DMSG(8,"should be true one hop neighbor \n");
    //DMSG(8,"parent_tuple_pt->N_status = %d MPR_linkv4 = %d SYM_LINKv4 = %d\n",parent_tuple_pt->N_status,MPR_LINKv4,SYM_LINKv4);
    if(parent_tuple_pt->N_status==MPR_LINKv4 || parent_tuple_pt->N_status==SYM_LINKv4) { //make sure neighbor is true one hop
      errortype=10;
      //no existing 2 hop neighbor with given twohop_addr
      // make and link them together
      //DMSG(7,"Adding and making two hop neighbor %s to ",twohop_addr.GetHostString());
      //DMSG(7,"%s\n",parent_tuple_pt->N_addr.GetHostString());
            
      updateMprs=1;
      tuple_pt=new NbrTuple; // make new neighbor
      tuple_pt->N_addr=twohop_addr;
      tuple_pt->hop=2;
      (tuple_pt->parents).QueueObject(parent_tuple_pt);// link child to parent node
      (parent_tuple_pt->children).QueueObject(tuple_pt); // link parent to child node
      nbr_2hop_list.QueueObject(tuple_pt);  // add to two hop list
      //tuple_pt is only valid for use as a 2 hop right now the queue time is not set up properly as Vtime for it is not known
    }
    else{
      errortype=11;
      // may make node and add to stepparents in the future
      //DMSG(8,"ignroing 2 link cause 1 hop is pending \n");
    }

  }
  //checkCurrentTable(errortype);
  //printCurrentTable(3);
  
  //DMSG(6,"Exit: Nrlolsr::update_2hop_nbr(onehop %s,twohop",onehop_addr.GetHostString());
  //DMSG(6," %s\n",twohop_addr.GetHostString());
}//end Nrlolsr::update_2hop_nbr(onehop,twohop)

void
Nrlolsr::remove_2hop_link(ProtoAddress oneaddr,ProtoAddress twoaddr){
  //DMSG(6,"Enter: Nrlolsr::remove_2hop_link(oneaddr %s,twoaddr ",oneaddr.GetHostString());
  //DMSG(6,"%s)\n",twoaddr.GetHostString());

  NbrTuple *tuple_pt, *child_pt, *parents;
  tuple_pt=nbr_list.FindObject(oneaddr);
  if(tuple_pt){ //should always pass
    child_pt=tuple_pt->children.FindObject(twoaddr);
    if(child_pt){ // should pass most of the time
      //DMSG(7,"Removing: 2 hop neighbor %s ",twoaddr.GetHostString()); 
      //DMSG(7,"two %s\n",oneaddr.GetHostString());
      // remove the link
      if((tuple_pt=child_pt->parents.FindObject(oneaddr))){ // check if its a parent or step parent 
	child_pt->parents.RemoveCurrent();
      }
      else if((tuple_pt=child_pt->stepparents.FindObject(oneaddr))){
	child_pt->stepparents.RemoveCurrent();
      } else {
	DMSG(0,"parent checking failed in remove_2hop_link! %s to %s at time %f \n",oneaddr.GetHostString(),twoaddr.GetHostString(),InlineGetCurrentTime());
      }
      tuple_pt->children.RemoveCurrent();
      // check to see if child lost last parent
      if(child_pt->parents.IsEmpty()){
	// lost last parent remove the node
	if(nbr_2hop_list.FindObject(twoaddr)) // may have been a stepparent removed
	  nbr_2hop_list.RemoveCurrent();
	if(!nbr_list.FindObject(twoaddr)){ //check to see if it was exclusivly a 2 hop neighbor
	  //get rid of step parents of removed node
	  for(parents=((child_pt->stepparents).PeekInit());parents!=NULL;parents=(child_pt->stepparents).PeekNext()){
	    if(parents!=NULL){
	      if(!parents->N_addr.HostIsEqual(tuple_pt->N_addr)){
		//if(parents->N_addr.IPv4HostAddr()!=tuple_pt->N_addr.IPv4HostAddr()){ //will neverhappen removed above
		if((parents->children).FindObject(child_pt->N_addr)) {
		  (parents->children).RemoveCurrent();
		} else {
		  DMSG(0,"missing childlink for node %s to child ",parents->N_addr.GetHostString());
		  DMSG(0,"%s in remove_2hop_link area: ",child_pt->N_addr.GetHostString());
		  DMSG(0,"%s stepparent was ",child_pt->N_addr.GetHostString());
		  DMSG(0,"%s\n",parents->N_addr.GetHostString());
		}
	      }
	    }
	  }
	  (child_pt->stepparents).Clear();
	  //get rid of step children of removed node
	  for(parents=((child_pt->children).PeekInit());parents!=NULL;parents=(child_pt->children).PeekNext()){
	    if(parents!=NULL){
	      if((parents->stepparents).FindObject(child_pt->N_addr)){
		(parents->stepparents).RemoveCurrent();
	      } else {
		//error statments shouldn't enter here
		if((parents->parents).FindObject(child_pt->N_addr)){
		  DMSG(0,"missing stepparents link for node %s to stepparent ",parents->N_addr.GetHostString());
		  DMSG(0,"%s in remove_2hop_link area: /n ",child_pt->N_addr.GetHostString());
		  DMSG(0,"but did find parent link! wasn't moved to stepparent correctly someplace in the past!");
		} else {
		  DMSG(0,"missing stepparents link for the node %s to stepparents ",parents->N_addr.GetHostString());
		  DMSG(0,"%s in remove_2hop_link area: no parent link found",child_pt->N_addr.GetHostString());
		}
		// end error statements
	      }
	    }
	  }
	  (child_pt->children).Clear();
	  delete child_pt;
	  //free(child_pt);
	}        
      }
    } else {
      // DMSG(0,"child_pt %d not found in tuple_pt %d's child list whild trying to remove in remove_2hop_link at time %f for node %d",twoaddr,oneaddr,InlineGetCurrentTime(),here_.addr_);  
    }
  } else {
    DMSG(0,"tuple_pt not found in nbr_list, trying to remove two hop %s to ",oneaddr.GetHostString());
    DMSG(0,"%s at time %f link doesn't exist!",twoaddr.GetHostString(),InlineGetCurrentTime());
  }
  //checkCurrentTable(40);
  //DMSG(6,"Exit: Nrlolsr::remove_2hop_link(oneaddr %s,twoaddr ",oneaddr.GetHostString());
  //DMSG(6,"%s)\n",twoaddr.GetHostString());
} //end remove_2hop_link(oneaddr,twoaddr)

void
Nrlolsr::addHnaInfo(ProtoAddress gwaddr,ProtoAddress subnetaddr,ProtoAddress subnetmask,UINT8 Vtime){
  //DMSG(6,"Enter: Nrlolsr::addHnaInfo(gwaddr %s, ",gwaddr.GetHostString());
  //DMSG(6,"subnetaddr %s, ",subnetaddr.GetHostString());
  //DMSG(6,"subnetmask %s, Vtime %d)\n",subnetmask.GetHostString(),Vtime);

  NbrTuple *tuple = NULL;
  bool notfound = true;
  //check to see if subnet address and mask is same as one that is directly used
  for(tuple=hnaAddresses.PeekInit();tuple!=NULL;tuple=hnaAddresses.PeekNext()){
    if(subnetaddr.HostIsEqual((tuple->N_addr)) && subnetmask.HostIsEqual((tuple->N_2hop_addr))){
      //DMSG(5,"finding matchs to local hna networks\n");
      fflush(stdout);
      //match found don't add hna 
      notfound = false;
    }
  }
  if(notfound) {
    //check for existing hna tuple and refresh if there
    tuple = hnaSet.FindObject(gwaddr);
    if(tuple){
      if(tuple->subnetMask.HostIsEqual(subnetmask) && tuple->N_2hop_addr.HostIsEqual(subnetaddr)){
	//DMSG(5,"found match with first entry\n");
	notfound = false;
	hnaSet.RemoveCurrent();
	tuple->N_time = InlineGetCurrentTime() + mantissatodouble(Vtime);
	hnaSet.QueueObject(tuple);
      }
      while((tuple = hnaSet.FindNextObject(gwaddr)) && notfound){
	if(tuple->N_2hop_addr.HostIsEqual(subnetaddr) && tuple->subnetMask.HostIsEqual(subnetmask)){
	  // found match remove and replace
	  notfound = false;
	  hnaSet.RemoveCurrent();
	  tuple->N_time = InlineGetCurrentTime() + mantissatodouble(Vtime);
	  hnaSet.QueueObject(tuple);
	}
      }
    }
    if(notfound){
      // add new hna to list
      tuple = new NbrTuple;
      tuple->N_addr=gwaddr;
      tuple->N_2hop_addr=subnetaddr;
      tuple->subnetMask=subnetmask;
      tuple->N_time = InlineGetCurrentTime() + mantissatodouble(Vtime);
      hnaSet.QueueObject(tuple);
    }
  }
  //DMSG(6,"Exit: Nrlolsr::addHnaInfo(gwaddr %s, ",gwaddr.GetHostString());
  //DMSG(6,"subnetaddr %s, ",subnetaddr.GetHostString());
  //DMSG(6,"subnetmask %s, Vtime %d)\n",subnetmask.GetHostString(),Vtime);
} //end Exit: Nrlolsr::addHnaInfo(gwaddr,subnetaddr,subnetmask,Vtime)

void
Nrlolsr::addTopologyInfo(ProtoAddress T_last, ProtoAddress T_dest, UINT16 T_seq, UINT16 delayValue, UINT8 Vtime){
  //DMSG(6,"Enter: Nrlolsr::addTopologyInfo(T_last %s, T_dest ",T_last.GetHostString());
  //DMSG(6,"%s, T_seq %d, delayValue %d, Vtime %d)\n",T_dest.GetHostString(),T_seq,delayValue,Vtime);
  //DMSG(7,"Adding T_last=%s ",T_last.GetHostString());
  //DMSG(7,"T_dest=%s ",T_dest.GetHostString());
  //DMSG(7,"mssn=%d to %s's table \n",T_seq,myaddress.GetHostString());
  NbrTuple *tuple = new NbrTuple;
  tuple->N_addr=T_last;
  tuple->N_2hop_addr=T_dest;
  tuple->seq_num=T_seq;
  tuple->N_time2=InlineGetCurrentTime()+mantissatodouble(Vtime); // wanted to make list out of order
  //tuple->N_time=CURRENT_TIME+Top_Hold_Time;
  //tuple->N_time=T_last;
  tuple->N_time=0;
  tuple->N_delay=delayValue;
  tuple->N_status=0;  //used for finding disjoint paths in makeRoutingTable
  topologySet.QueueObjectAddressSort(tuple); //sorts by address
  //topologySet.QueueObject(tuple); //sorts by timeout value
  //DMSG(6,"Exit: Nrlolsr::addTopologyInfo(T_last %s, T_dest ",T_last.GetHostString());
  //DMSG(6,"%s, T_seq %d, delayValue %d, Vtime %d)\n",T_dest.GetHostString(),T_seq,delayValue,Vtime);
}

int
Nrlolsr::updateTopology(ProtoAddress T_last, UINT16 T_seq){
  //DMSG(6,"Enter: Nrlolsr::updateTopology(T_last %s,T_seq %d)\n",T_last.GetHostString(),T_seq);
  NbrTuple *tuple = topologySet.FindObject(T_last);
  if(tuple){
    //DMSG(9,"getting addr %s mssn %d \n",T_last.GetHostString(),T_seq);
    // checking to see if seq_num<T_seq number if so update
    // note that compiler says this statement is always true for some reason.  Look at it later.  May need to be fixed.
    if(T_seq-tuple->seq_num<MAXMSSN/2 && T_seq-tuple->seq_num>=0 || (T_seq < MAXMSSN && tuple->seq_num > T_seq + MAXMSSN/2)){ // is new data update
      //remove all old entries and prepare for updated ones
      while(tuple){
	//DMSG(7,"Removing from %s topology tuple %d in updateTopology \n",myaddress.GetHostString(),T_last);
	topologySet.RemoveCurrent();
	delete tuple;
	//free(tuple);
	tuple=topologySet.FindObject(T_last);
	
      }
      //printTopology(3);
      return 1;
    } else {
      //DMSG(9,"mssn duplicate entry \n");
      return 0;
    }
  }
  //DMSG(6,"Exit: Nrlolsr::updateTopology(T_last %s,T_seq %d)\n",T_last.GetHostString(),T_seq);
  return 1;
}

void
Nrlolsr::update_mprselector(ProtoAddress id,int status) {
  //DMSG(6,"Enter: Nrlolsr::update_mprselector(id %s,int %d)\n",id.GetHostString(),status);
  //using the slighly bloated NBRQueue list for simple list
  NbrTuple *tuple_pt;
  switch(status){
  case SYM_LINKv4: // remove from list if there
    //DMSG(9,"in update_mprselector with SYM status for neighbor %s\n",id.GetHostString());
    tuple_pt=mprSelectorList.FindObject(id);
    if(tuple_pt){

      mprSelectorList.RemoveCurrent();
      delete tuple_pt;
      //free(tuple_pt);
      updateSM();
    }
    break;
  case MPR_LINKv4: // add to list if not there
    //DMSG(9,"in update_mprselector with MPR status for neighbor %s\n",id.GetHostString());
    tuple_pt=mprSelectorList.FindObject(id);
    if(!tuple_pt){
      //DMSG(7,"Adding neighbor %s to my mpr selctor list\n",id.GetHostString());
      tuple_pt=new NbrTuple;
      tuple_pt->N_addr=id;
      mprSelectorList.QueueObject(tuple_pt);
      updateSM();
    }
    break;
  }
  //DMSG(6,"Exit: Nrlolsr::update_mprselector(id %s,int %d)\n",id.GetHostString(),status);
}
void
Nrlolsr::updateSM(){ // updates shared memory that is used by other processes to see the mpr status. (smart flooding)
#ifndef SIMULATE
#ifdef UNIX
  //DMSG(6,"Enter: Nrlolsr::updateSM()\n");
  if(ipvMode==ProtoAddress::IPv4){
    NbrTuple *tuple_pt=NULL;
    int i=0;
    for(tuple_pt=mprSelectorList.PeekInit();tuple_pt!=NULL;tuple_pt=mprSelectorList.PeekNext()){
      mprselectors.addrs[i++]=tuple_pt->N_addr.IPv4GetAddress();
    } 
    mprselectors.addrs[i]=0;
    //for(tuple_pt=nbr_list.PeekInit();tuple_pt!=NULL;tuple_pt=nbr_list.PeekNext()){
    //  mprselectors.addrs[i++]=tuple_pt->N_addr.IPv4HostAddr();
    //}
    MPRSELPublishUpdate(handle_mprsel,&mprselectors);
  }
  //DMSG(6,"Exit: Nrlolsr::updateSM()\n");
#endif//ifdef UNIX
#endif// SIMULATE
  return;
}

// seleect mprs as outlined in the spec v8
// I recomend that you read and understand the spec and not just my poor explination of what its doing
// the way mprs are seleced: first pick the neighbors which are the only route to some nodes
// they have to be picked unless one hop neighbor has a willingness factor of never in which case the 2 hop 
// neighbor should not be in the list.  Then add in all neighbors with a willingness of ALWAYS.  Procede to 
// step though the williness factors starting from the most willing picking the node that connects to the most 
// uncovered 2 hop neighbors and repeat breaking ties by picking the node connected to the most nodes(covered included).
// If 2 hop neighbors are still uncovered go down and check the next willingness group.
// thats what this code does
void
Nrlolsr::selectmpr() {
  //DMSG(6,"Enter: Nrlolsr::selectmpr()\n");
  int numberOfParents;
  NbrTuple *child, *parent, *newmpr=NULL;
  //printCurrentTable(3);
  //DMSG(8," initializing mpr and incrimenting %s's mssn number which is now %d \n",myaddress.GetHostString(),mssn+1);
  mssn++;
  mssn=mssn % MAXMSSN;
  for(parent=nbr_list.PeekInit();parent!=NULL;parent=nbr_list.PeekNext()){
    if(parent!=NULL){
      if(parent->N_status==MPR_LINKv4)
	parent->N_status=SYM_LINKv4;
      parent->tdegree=0;
      parent->cdegree=0;
    }
  }
  //  DMSG(11," assigining degrees \n");
  //  fflush(stdout);


  for(child=nbr_2hop_list.PeekInit();child!=NULL;child=nbr_2hop_list.PeekNext()){
    if(child!=NULL){
      if(child->hop==2){
	numberOfParents=0;
	//DMSG(11,"%s is adding to - ",child->N_addr.GetHostString());
	//fflush(stdout);
	for(parent=(child->parents).PeekInit();parent!=NULL;parent=(child->parents).PeekNext()){
	  if(parent!=NULL){
	    if((parent->N_status==MPR_LINKv4 || parent->N_status==SYM_LINKv4) && parent->N_willingness!=WILL_NEVER){
	      //DMSG(11,"%s %d:",parent->N_addr.GetHostString(),parent->cdegree+1);
	      //fflush(stdout);
	      numberOfParents++;
	      parent->tdegree++;
	      parent->cdegree++;
	    }
	  }
	}
	//DMSG(11,"\n");
	if(numberOfParents==1){// parent node must be selected at mpr
	  parent=(child->parents).PeekInit();
	  makempr(parent);
	}
      }
    }
    //DMSG(11 ,"\n");
    //fflush(stdout);
  }
  //DMSG(9,"selecting biggest degrees \n");
  //fflush(stdout);

  for(parent=nbr_list.PeekInit();parent!=NULL;parent=nbr_list.PeekNext()){
    if(parent->N_willingness == WILL_ALWAYS){
      makempr(parent);
    }
  }
  // go through and select highest willingness nodes with the biggest degree
   for(int currentwillingness = 6;currentwillingness>0;currentwillingness--){
     int highestdegree=1;
     while(highestdegree){
      highestdegree=0;
      for(parent=nbr_list.PeekInit();parent!=NULL;parent=nbr_list.PeekNext()){
	if(parent->N_willingness == currentwillingness){
	  if((int)(parent->cdegree)>(int)highestdegree){
	    //DMSG(11,"%s is new highest at %d count \n",parent->N_addr.GetHostString(),parent->cdegree);
	    highestdegree=parent->cdegree;
	    newmpr=parent;
	  }
	}
      }
      //DMSG(11,"%d is highest degree",highestdegree);
      if(highestdegree)
	makempr(newmpr);
    }
  }
  //DMSG(6,"Enter: Nrlolsr::selectmpr()\n");
}

// this makes a node an mpr and updates the current nodal degree of all the other one hop nodes
void
Nrlolsr::makempr(NbrTuple *parent) { // updates the current degrees with the parent node selected
  //DMSG(6,"Enter: Nrlolsr::makempr(*parent %s)\n",parent->N_addr.GetHostString());
  NbrTuple *child, *stepparent;
  if(parent->N_status!=MPR_LINKv4){ // check to see if its an mpr already
    parent->N_status=MPR_LINKv4;
    //DMSG(8,"%s is new mpr of ",parent->N_addr.GetHostString());
    //DMSG(8,"%s \n",myaddress.GetHostString());
    for(child=(parent->children).PeekInit();child!=NULL;child=(parent->children).PeekNext()){
      if(child!=NULL){
	//DMSG(9,"%d hop of %s :",child->hop,child->N_addr.GetHostString());
	if(child->hop==2){
	  for(stepparent=(child->parents).PeekInit();stepparent!=NULL;stepparent=(child->parents).PeekNext()){
	    if(stepparent!=NULL){
	      stepparent->cdegree--;
	    }
	  }
	}
      } 
    }
  }
  //DMSG(6,"Exit: Nrlolsr::makempr(*parent %s)\n",parent->N_addr.GetHostString());
}

// when making a new routing table first the old table is stored.  Then the new one is made all new from the valid topology, 
// and neighbor tables.  Then routes are added or changed depending on if they are new or not.  Then entries in the old
// routing table which are not coverd yet are removed.  The method on how to create a routing table is covered in the OLSR 
// specification.  One interteresting point to mention is that the way the lists of the tables are ordered makes a difference
// in the outcome of the resulting routing table. 
void 
Nrlolsr::makeNewRoutingTable (){ 
  //DMSG(6,"Enter: Nrlolsr::makeNewRoutingTable()\n");
  NbrTuple *nb, *nb2=NULL, *top_tuple, *old_tuple, *tuple = routeTable.PeekInit();
  int wasnewentry=0, queueIndex=0,foundnewlink=0;
  double smallestDelay=0 ;
  //  printRoutingTable(2);
  //clearing old routing table
  oldRouteTable.Clear();
  while(tuple){
    routeTable.RemoveCurrent();
    //DMSG(10,"copying entry in routing table to extra queue \n");
    oldRouteTable.QueueObject(tuple);
    tuple=routeTable.PeekInit();
  }
  // making new queue to use 
  extraQueue.Clear();
  for(top_tuple=topologySet.PeekInit();top_tuple!=NULL;top_tuple=topologySet.PeekNext()){
    extraQueue.QueueObject(top_tuple);
  }
  //adding one hops
  for(nb=nbr_list.PeekInit();nb!=NULL;nb=nbr_list.PeekNext()){
    if(nb!=NULL){
      if(nb->hop==1 && (nb->N_status==SYM_LINKv4 || nb->N_status==MPR_LINKv4)){
	tuple=new NbrTuple;
	tuple->N_time=queueIndex--; //used queue object at head (which is faster way)
  	tuple->N_addr=nb->N_addr;  // really R_dest
  	tuple->N_2hop_addr=nb->N_addr; // really R_next
  	tuple->hop=1;                    // really R_dist
	tuple->N_status=-1;
	routeTable.QueueObject(tuple);
	//	realRouteTable->addHostRoute(tuple->N_addr,tuple->N_2hop_addr);
	wasnewentry=1;
	// removing links pointing to this node
	for(top_tuple=extraQueue.PeekInit();top_tuple!=NULL;top_tuple=extraQueue.PeekNext()){
	  if(top_tuple->N_2hop_addr.HostIsEqual(tuple->N_addr)){
	    extraQueue.RemoveCurrent();
	  }
	}
      }
    }
  }
  while(wasnewentry){
    //add on smallest value nodes
    wasnewentry=0;
    foundnewlink=0;
    for(top_tuple=extraQueue.PeekInit();(top_tuple!=NULL) && (foundnewlink==0);top_tuple=extraQueue.PeekNext()){
      for(tuple=routeTable.PeekInit();(tuple!=NULL) && (foundnewlink==0);tuple=routeTable.PeekNext()){
	if(top_tuple->N_addr.HostIsEqual(tuple->N_addr) && !(top_tuple->N_2hop_addr).HostIsEqual(myaddress)){ //T_last==R_dest | doesn't point back to here | delay is smaller
	  nb=tuple;
	  nb2=top_tuple;
	  foundnewlink=1;
	}  
      }
    }
    if(foundnewlink){
      // add the link nb to routing table and do over again
      //printRoutingTable(3);
      wasnewentry=1;
      tuple = new NbrTuple;
      tuple->N_time=queueIndex--;
      tuple->N_addr=nb2->N_2hop_addr;  //is R_dest=T_dest
      tuple->N_2hop_addr=nb->N_2hop_addr;       //is R_next=R_next
      tuple->N_delay=(UINT16)(smallestDelay*(double)OLSRMAXDELAY);
      tuple->hop=nb->hop+1;
      tuple->N_status=0;
      routeTable.QueueObject(tuple); 
      //realRouteTable->addHostRoute(tuple->N_addr,tuple->N_2hop_addr);
      //have to remove from extraQueue tuples point at node just added
      for(top_tuple=extraQueue.PeekInit();top_tuple!=NULL;top_tuple=extraQueue.PeekNext()){
	if(top_tuple->N_2hop_addr.HostIsEqual(nb2->N_2hop_addr)){
	  extraQueue.RemoveCurrent();
	}
      }
    }
  }
  // go though and cleanly update the real routing table  
  
  //add direct routes first
  for(tuple=routeTable.PeekInit();tuple!=NULL;tuple=routeTable.PeekNext()){
    if(tuple->N_addr.HostIsEqual((tuple->N_2hop_addr))){ //only do direct routes in the section
      if((old_tuple = oldRouteTable.FindObject(tuple->N_addr))){
	//old host route existed check to see if current choice is different
  	if(!old_tuple->N_2hop_addr.HostIsEqual((tuple->N_2hop_addr))){// if the gateways are differnet change the route (old one was host route)
	  //DMSG(6,"Setting direct route %s\n",tuple->N_addr.GetHostString());
	  //DMSG(6,"metric before call %d\n",tuple->hop);
	  realRouteTable->SetRoute(tuple->N_addr,hostMaskLength,invalidAddress,interfaceIndex,tuple->hop);
	} else {     
	  //DMSG(6,"Not changing direct route to %s\n",tuple->N_addr.GetHostString());
	}
	oldRouteTable.RemoveCurrent();
	delete old_tuple;
	//free(old_tuple);
      } else {
	//old host route did not exist just add to real table
	//DMSG(6,"Adding new direct route %s\n",tuple->N_addr.GetHostString());
	//DMSG(8,"metric before call %d\n",tuple->hop);
	realRouteTable->SetRoute(tuple->N_addr,hostMaskLength,invalidAddress,interfaceIndex,tuple->hop);
	//realRouteTable->SetDirectHostRoute(tuple->N_addr,interfaceIndex);
      }
    }
  }
  //add host routes second
  for(tuple=routeTable.PeekInit();tuple!=NULL;tuple=routeTable.PeekNext()){
    if(!tuple->N_addr.HostIsEqual((tuple->N_2hop_addr))){ //check to make sure is a host route 
      if((old_tuple = oldRouteTable.FindObject(tuple->N_addr))){
	//DMSG(6,"old route existed for current host route\n");
	//old route existed for current host route
	if(!old_tuple->N_2hop_addr.HostIsEqual((tuple->N_2hop_addr))){// if the gateways are differnet change the route
	  //DMSG(6,"Setting host route %s to ",tuple->N_addr.GetHostString());
	  //DMSG(6,"%s\n",tuple->N_2hop_addr.GetHostString());
	  realRouteTable->SetRoute(tuple->N_addr,hostMaskLength,tuple->N_2hop_addr,interfaceIndex,tuple->hop); 
	  if(false) {//ipvMode==IPv6){ // this is cause set route functions differently in v4 mode than v6 fix this brian
	    if(old_tuple->N_2hop_addr.HostIsEqual((old_tuple->N_addr))){ //used to be a direct route delete direct route
	      //DMSG(6,"Removing old direct route to %s\n",old_tuple->N_addr.GetHostString());
	      if(!realRouteTable->DeleteRoute(old_tuple->N_addr,hostMaskLength,invalidAddress,interfaceIndex)){//,invalidAddr)){
		DMSG(0,"Nrlolsr::makeNewRoutingTable() Error removing direct route to %s\n",old_tuple->N_addr.GetHostString());
	      }
	    } else { // used to be a host route delete host route
	      //DMSG(6,"Removing old host route %s ",old_tuple->N_addr.GetHostString());
	      //DMSG(6,"via %s\n",old_tuple->N_2hop_addr.GetHostString());
	      if(!realRouteTable->DeleteRoute(old_tuple->N_addr,hostMaskLength,old_tuple->N_2hop_addr,interfaceIndex)){//,old_tuple->N_2hop_addr)){
		DMSG(0,"Nrlolsr::makeNewRoutingTable() Error removing host route %s via ",old_tuple->N_addr.GetHostString());
		DMSG(0,"%s\n",old_tuple->N_2hop_addr.GetHostString());
	      }
	    }
	  }
	} else {
	  //DMSG(6,"Not changing host route to %s via",tuple->N_addr.GetHostString());
	  //DMSG(6," %s\n",tuple->N_2hop_addr.GetHostString());
	}
	oldRouteTable.RemoveCurrent();
	delete old_tuple;
	//free(old_tuple);
      } else {
	//old host route did not exist just add to real table
	//DMSG(6,"Adding new host route dest=%s route=",tuple->N_addr.GetHostString());
	//DMSG(6,"%s\n",tuple->N_2hop_addr.GetHostString());
	realRouteTable->SetRoute(tuple->N_addr,hostMaskLength,tuple->N_2hop_addr,interfaceIndex,tuple->hop);
      }
    }
  }
  old_tuple=oldRouteTable.PeekInit();
  while(old_tuple){ //loop to clean extraQueue and remove old routes
    oldRouteTable.RemoveCurrent();
    if(old_tuple->N_addr.HostIsEqual((old_tuple->N_2hop_addr))){
      //DMSG(6,"Removing direct route to %s\n",old_tuple->N_addr.GetHostString());
      //ProtoAddress invalidAddress;
      //invalidAddress.Init();
      if(!realRouteTable->DeleteRoute(old_tuple->N_addr,hostMaskLength,invalidAddress,interfaceIndex)){
	DMSG(0,"Nrlolsr::makeNewRoutingTable() Error removing direct route to %s\n",old_tuple->N_addr.GetHostString());
      }
    } else {
      //DMSG(6,"Removing route to %s via ",old_tuple->N_addr.GetHostString());
      //DMSG(6,"%s\n",old_tuple->N_2hop_addr.GetHostString());
      if(!realRouteTable->DeleteRoute(old_tuple->N_addr,hostMaskLength,old_tuple->N_2hop_addr,interfaceIndex)){
	DMSG(0,"Nrlolsr::makeNewRoutingTable() Error removing host route to %s via",old_tuple->N_addr.GetHostString());
	DMSG(0,"%s\n",old_tuple->N_2hop_addr.GetHostString());
      }
    }
    delete old_tuple;
    //free(old_tuple); 
    old_tuple=oldRouteTable.PeekInit();
  }
  //DMSG(6,"Finished updating route table\n");

  
  //printCurrentTable(7);
  //DMSG(6,"Exit: Nrlolsr::makeNewRoutingTable()\n");
} //end Nrlolsr::makeNewRoutingTable()

void
Nrlolsr::addHnaRoutes(){
  //DMSG(6,"Enter: Nrlolsr::addHnaRoutes()\n");
  NbrTuple *routeTuple, *hnaTuple, *addedHnaTuple, *tuple = hnaRoutes.PeekInit();
  bool nomatch, foundhnamatch;
  int addedwithhopcount=0;
  // save old hna route table to oldRoutetable
  oldRouteTable.Clear();
  while(tuple){
    hnaRoutes.RemoveCurrent();
    //DMSG(10,"copying entry in routing table to extra queue \n");
    oldRouteTable.QueueObject(tuple);
    tuple=hnaRoutes.PeekInit();
  }
  // next for loop is for updating hnaRoutes
  for(hnaTuple = hnaSet.PeekInit();hnaTuple!=NULL;hnaTuple=hnaSet.PeekNext()){
    nomatch = true;
    addedwithhopcount = 0;
    for(addedHnaTuple = hnaRoutes.PeekInit();addedHnaTuple!=NULL && nomatch;addedHnaTuple=hnaRoutes.PeekNext()){
      if(hnaTuple->N_2hop_addr.HostIsEqual((addedHnaTuple->N_2hop_addr)) && 
	 hnaTuple->subnetMask.HostIsEqual((addedHnaTuple->subnetMask))) { //checking for matching subnet address
	addedwithhopcount=addedHnaTuple->hop;
	nomatch = false;
	break; //I hate using breaks! and I hate how for loops do the last statement even when its conditinal is false making me use breaks!
      }    
    }
    for(routeTuple=routeTable.PeekInit();routeTuple!=NULL;routeTuple=routeTable.PeekNext()){
      if(routeTuple->N_addr.HostIsEqual((hnaTuple->N_addr))){ //checking R_dest against hna gateway address
	if(nomatch) {
	  //add new hna info to hna routing table 
	  tuple = new NbrTuple;
	  tuple->N_addr=routeTuple->N_2hop_addr; //R_next
	  tuple->N_2hop_addr=hnaTuple->N_2hop_addr; //sbna
	  tuple->subnetMask=hnaTuple->subnetMask; //mask
	  tuple->hop=routeTuple->hop;
	  hnaRoutes.QueueObject(tuple);
	} else if (routeTuple->hop<addedwithhopcount) { // check to see if current match is better than old
	  //fprintf(stdout,"removing duplicate hna with longer hop count ");
	  //remove and free old
	  hnaRoutes.RemoveCurrent();//its one step back! grrr stupid for loop
	  delete addedHnaTuple;
	  //free(addedHnaTuple);
	  //add new hna info to hna routing table
	  tuple = new NbrTuple;
	  tuple->N_addr=routeTuple->N_2hop_addr; //R_next
	  tuple->N_2hop_addr=hnaTuple->N_2hop_addr; //sbna
	  tuple->subnetMask=hnaTuple->subnetMask; //mask
	  tuple->hop=routeTuple->hop;
	  hnaRoutes.QueueObject(tuple);
	} else {
	  // do nothing already added better route
	}
      }
    } 
  }
  /*fprintf(stdout,"             old table \n");
  for(tuple = oldRouteTable.PeekInit();tuple!=NULL;tuple = oldRouteTable.PeekNext()){
  fprintf(stdout,"R_dest %s ",tuple->N_addr.GetHostString());
  fprintf(stdout,"sbna %s ",tuple->N_2hop_addr.GetHostString());
  fprintf(stdout,"mask %s\n",tuple->subnetMask.GetHostString());
  }
  fprintf(stdout,"           new table \n");
  for(tuple = hnaRoutes.PeekInit();tuple!=NULL;tuple = hnaRoutes.PeekNext()){
  fprintf(stdout,"R_dest %s ",tuple->N_addr.GetHostString());
  fprintf(stdout,"sbna %s ",tuple->N_2hop_addr.GetHostString());
  fprintf(stdout,"mask %s\n",tuple->subnetMask.GetHostString());
  }*/
  //hnaRoutes are up to date add to real routing table
  for(routeTuple = hnaRoutes.PeekInit();routeTuple!=NULL;routeTuple = hnaRoutes.PeekNext()){
    foundhnamatch = false;
    for(tuple = oldRouteTable.PeekInit();tuple!=NULL;tuple = oldRouteTable.PeekNext()){ 
      if(routeTuple->N_2hop_addr.HostIsEqual((tuple->N_2hop_addr)) &&
	 routeTuple->subnetMask.HostIsEqual((tuple->subnetMask))){	
	foundhnamatch = true;
	if(!(routeTuple->N_addr.HostIsEqual((tuple->N_addr)))) {
	  //found existing differet route change it
	  //DMSG(6,"HNA Setting net route to %s / %d via",routeTuple->N_2hop_addr.GetHostString(),routeTuple->subnetMask.GetPrefixLength());
	  //DMSG(6," %s\n",routeTuple->N_addr.GetHostString());
	  realRouteTable->SetRoute(routeTuple->N_2hop_addr,routeTuple->subnetMask.GetPrefixLength(),routeTuple->N_addr,interfaceIndex,routeTuple->hop);
	  if(false){//ipvMode==IPv6){
	    //DMSG(6,"HNA Delete net route %s / %d via",tuple->N_2hop_addr.GetHostString(),tuple->subnetMask.GetPrefixLength());
	    //DMSG(6," %s\n",tuple->N_addr.GetHostString());
	    if(!realRouteTable->DeleteRoute(tuple->N_2hop_addr,tuple->subnetMask.GetPrefixLength(),tuple->N_addr,interfaceIndex)){//,tuple->N_addr,interfaceIndex)){
	      DMSG(0,"Nrlolsr::addHnaRoutes() Error removing net route\n");
	    }
	  }
	  // don't need next three lines
	  //if(!realRouteTable->DeleteRoute(tuple->N_2hop_addr,tuple->subnetMask,tuple->N_addr,interfaceIndex)){
	  //  DMSG(0,"removing net route error\n");
	  //}
	  
	} else {
	  //DMSG(6,"HNA Found matching hna entry in current route table for %s leaving alone\n",routeTuple->N_addr.GetHostString());
	  //found same route leave alone
	}
	//free up oldroutetable entry
	oldRouteTable.RemoveCurrent();
	delete tuple;
	//free(tuple);
      } 
    }
    if (!foundhnamatch) {
      //DMSG(6,"HNA Adding new route to %s / %d via ",routeTuple->N_2hop_addr.GetHostString(),routeTuple->subnetMask.GetPrefixLength());
      //DMSG(6,"%s\n",routeTuple->N_addr.GetHostString());
      //found new route and adding it here
      realRouteTable->SetRoute(routeTuple->N_2hop_addr,routeTuple->subnetMask.GetPrefixLength(),routeTuple->N_addr,interfaceIndex,routeTuple->hop);
    }
  }
  // clean up oldRouteTable
  tuple=oldRouteTable.PeekInit();
  while(tuple){ //loop to clean extraQueue and remove old routes
    oldRouteTable.RemoveCurrent();
    //remove old route
    //DMSG(6,"HNA Removing old route %s / %d via ",tuple->N_2hop_addr,tuple->subnetMask.GetPrefixLength());
    //DMSG(6," %s\n",tuple->N_addr);
    if(!realRouteTable->DeleteRoute(tuple->N_2hop_addr,tuple->subnetMask.GetPrefixLength(),tuple->N_addr,interfaceIndex)){//,tuple->N_addr)){
      DMSG(0,"error removing net route\n");
    }
    delete tuple;
    //free(tuple); 
 
    tuple=oldRouteTable.PeekInit();
  }
  //DMSG(6,"Exit: Nrlolsr::addHnaRoutes()\n");
} // end Nrlolsr::addHnaRoutes()

int 
Nrlolsr::WasForwarded(ProtoAddress addr,UINT16 dseqno){
  //DMSG(6,"Enter: Nrlolsr::WasForwarded(addr %s,dseqno %d\n",addr.GetHostString(),dseqno);
  NbrTuple *tuple = forwardTable.FindObject(addr);
  if(addr.HostIsEqual(myaddress)){
    return 1;
  }
  while(tuple){
    if(tuple->seq_num==dseqno){
      //DMSG(6,"Exit: Nrlolsr::WasForwarded(addr %s,dseqno %d\n",addr.GetHostString(),dseqno);
      return 1;
    }
    tuple = forwardTable.FindNextObject(addr);
  }
  //DMSG(6,"Exit: Nrlolsr::WasForwarded(addr %s,dseqno %d\n",addr.GetHostString(),dseqno);
  return 0;
}// end Nrlolsr::WasForwarded

void
Nrlolsr::addForwarded(ProtoAddress forwardaddr,UINT16 dseqno){
  //DMSG(6,"Enter: Nrlolsr::addForwarded(forwardaddr %s,dseqno %d\n",forwardaddr.GetHostString(),dseqno);
  NbrTuple *tuple = forwardTable.FindObject(forwardaddr);
  while(tuple){
    if(tuple->seq_num==dseqno){ 
      tuple->N_time = InlineGetCurrentTime()+D_Hold_Time;
      //DMSG(6,"Exit: Nrlolsr::addForwarded(forwardaddr %s,dseqno %d\n",forwardaddr.GetHostString(),dseqno);
      return;
    }
    tuple = forwardTable.FindNextObject(forwardaddr);
  }  
  tuple = new NbrTuple;
  tuple->seq_num = dseqno;
  tuple->N_addr = forwardaddr;
  tuple->N_time = InlineGetCurrentTime()+D_Hold_Time;
  forwardTable.QueueObject(tuple);
  //DMSG(6,"Exit: Nrlolsr::addForwarded(forwardaddr %s,dseqno %d\n",forwardaddr.GetHostString(),dseqno);
}

int
Nrlolsr::IsDuplicate(ProtoAddress addr,UINT16 dseqno){
  //DMSG(6,"Enter: Nrlolsr::IsDuplicate(addr %s,dseqno %d)\n",addr.GetHostString(),dseqno);
  NbrTuple *tuple = duplicateTable.FindObject(addr);
  printDuplicateTable(8);
  if(addr.HostIsEqual(myaddress)){
    //DMSG(6,"Exit: Nrlolsr::IsDuplicate(addr %s,dseqno %d)\n",addr.GetHostString(),dseqno);
    return 1;
  }
  while(tuple){
    if(tuple->seq_num==dseqno){ 
      //DMSG(1,"%s with seq num %d is DUP!",addr.GetHostString(),dseqno);
      //DMSG(6,"Exit: Nrlolsr::IsDuplicate(addr %s,dseqno %d)\n",addr.GetHostString(),dseqno);
      return 1;
    }
    tuple = duplicateTable.FindNextObject(addr);
  }
  //DMSG(6,"Exit: Nrlolsr::IsDuplicate(addr %s,dseqno %d)\n",addr.GetHostString(),dseqno);
  return 0;
}

// add entry addr and dseqno to duplicate table
void
Nrlolsr::addDuplicate(ProtoAddress dupaddr,UINT16 dseqno){
  //DMSG(6,"Enter: Nrlolsr::addDuplicate(dupaddr %s,dseqno %d)\n",dupaddr.GetHostString(),dseqno);
  NbrTuple *tuple = duplicateTable.FindObject(dupaddr);
  while(tuple){
    if(tuple->seq_num==dseqno){ 
      tuple->N_time = InlineGetCurrentTime()+D_Hold_Time;
      //DMSG(6,"Exit: Nrlolsr::addDuplicate(dupaddr %s,dseqno %d)\n",dupaddr.GetHostString(),dseqno);
      return;
    }
    tuple = duplicateTable.FindNextObject(dupaddr);
  }  
  tuple = new NbrTuple;
  tuple->seq_num = dseqno;
  tuple->N_addr = dupaddr;
  tuple->N_time = InlineGetCurrentTime()+D_Hold_Time;
  duplicateTable.QueueObject(tuple);
  printDuplicateTable(4);
  //DMSG(6,"Exit: Nrlolsr::addDuplicate(dupaddr %s,dseqno %d)\n",dupaddr.GetHostString(),dseqno);
}


// printing functions for debuging code
void 
Nrlolsr::printDuplicateTable(int debuglvl){
  if(olsrDebugValue>=debuglvl){
    NbrTuple *tuple;
    //DMSG(debuglvl,"------- %s's duplicate table --------\n",myaddress.GetHostString());
    for(tuple=duplicateTable.PrintPeekInit();tuple!=NULL;tuple=duplicateTable.PrintPeekNext()){
      if(tuple!=NULL){
	//DMSG(debuglvl," D_Addr= %s D_Seqn= %d D_time= %f \n",tuple->N_addr.GetHostString(), tuple->seq_num, tuple->N_time);
      }
    }
    //DMSG(debuglvl,"------- end duplicate table -------- \n");
  }  
}
void 
Nrlolsr::printHnaTables(int debuglvl){
  if(olsrDebugValue>=debuglvl){
    NbrTuple *tuple;
    //print out to  debug file
    DMSG(debuglvl,"***************%s's local hna list **************\n",myaddress.GetHostString());
    for(tuple=hnaAddresses.PrintPeekInit();tuple!=NULL;tuple=hnaAddresses.PrintPeekNext()){
      DMSG(debuglvl,"Subnetaddress %s ",tuple->N_addr.GetHostString());
      DMSG(debuglvl,"subnetmask %s\n",tuple->N_2hop_addr.GetHostString());
    }
    DMSG(debuglvl,"***************end local hna list  **************\n\n");
    DMSG(debuglvl,"***************%s's hnaSet list ***************\n",myaddress.GetHostString());
    for(tuple=hnaSet.PrintPeekInit();tuple!=NULL;tuple=hnaSet.PrintPeekNext()){
      DMSG(debuglvl,"R_dest %s ",tuple->N_addr.GetHostString());
      DMSG(debuglvl,"subnetaddr %s ",tuple->N_2hop_addr.GetHostString());
      DMSG(debuglvl,"subnetmask %s time %f\n",tuple->subnetMask.GetHostString(),tuple->N_time);
    }
    DMSG(debuglvl,"***************end hna set list  **************\n\n");
    DMSG(debuglvl,"***************%s's hnaRoutes list ***************\n",myaddress.GetHostString());
    for(tuple=hnaRoutes.PrintPeekInit();tuple!=NULL;tuple=hnaRoutes.PrintPeekNext()){
      DMSG(debuglvl,"R_next %s ",tuple->N_addr.GetHostString());
      DMSG(debuglvl,"subnetaddr %s ",tuple->N_2hop_addr.GetHostString());
      DMSG(debuglvl,"subnetmask %s\n",tuple->subnetMask.GetHostString());
    }
    DMSG(debuglvl,"***************end hna set list  **************\n\n");
  }
}

void
Nrlolsr::printRoutingTable(int debuglvl){
  if(olsrDebugValue>=debuglvl){
    NbrTuple *tuple;
    DMSG(debuglvl,"------- %s's routing table at time %f --------\n",myaddress.GetHostString(),InlineGetCurrentTime());
    for(tuple=routeTable.PrintPeekInit();tuple!=NULL;tuple=routeTable.PrintPeekNext()){
      if(tuple!=NULL){
	DMSG(debuglvl," R_dest= %s ",tuple->N_addr.GetHostString());
	DMSG(debuglvl,"R_next=%s R_dist=%d iteration=%d delay=%d\n",tuple->N_2hop_addr.GetHostString(),tuple->hop,tuple->N_status,tuple->N_delay);
      }
    }
    DMSG(debuglvl,"------- end routing table -------- \n");
  }
}

void
Nrlolsr::printHnaLinks(){
    //print out stdout for use with cmap
#ifndef SIMULATE
#ifdef UNIX
  NbrTuple *tuple;
  if(olsrDebugValue>=2){
    FILE *fid = popen("date -u +%T","r");
    char dateBuffer[10];
    fgets(dateBuffer,9,fid);
    pclose(fid);
    fprintf(stdout,"Hna-Networks List: %s.%06d\n",dateBuffer,GetLittleTime());
    for(tuple=hnaAddresses.PrintPeekInit();tuple!=NULL;tuple=hnaAddresses.PrintPeekNext()){
      fprintf(stdout,"%s -> ",myaddress.GetHostString());
      fprintf(stdout,"%s/%d\n",tuple->N_addr.GetHostString(),tuple->N_2hop_addr.GetPrefixLength());
    } 
    for(tuple=hnaSet.PrintPeekInit();tuple!=NULL;tuple=hnaSet.PrintPeekNext()){
      fprintf(stdout,"%s -> ",tuple->N_addr.GetHostString());
      fprintf(stdout,"%s/%d\n",tuple->N_2hop_addr.GetHostString(),tuple->subnetMask.GetPrefixLength());
    }
    fprintf(stdout,"End of Hna-Networks List.\n");
    fflush(stdout);
  }   
#endif //UNIX
#endif //SIMULATE
}

void
Nrlolsr::printLinks(){
#ifndef SIMULATE
#ifdef UNIX
  NbrTuple *tuple,*nb;
  if(olsrDebugValue>=1){
    FILE *fid = popen("date -u +%T","r");
    char dateBuffer[10];
    fgets(dateBuffer,9,fid);
    pclose(fid);
    fprintf(stdout,"Routing-Links List: %s.%06d\n",dateBuffer,GetLittleTime());
    for(nb=nbr_list.PrintPeekInit();nb!=NULL;nb=nbr_list.PrintPeekNext()){
      if(nb->N_status==SYM_LINKv4 || nb->N_status==MPR_LINKv4){
	fprintf(stdout,"%s -> ",myaddress.GetHostString());
	fprintf(stdout,"%s\n",nb->N_addr.GetHostString());      
      }
    }
    for(tuple=topologySet.PrintPeekInit();tuple!=NULL;tuple=topologySet.PrintPeekNext()){
      if(tuple!=NULL){
	fprintf(stdout,"%s -> ",tuple->N_addr.GetHostString());
	fprintf(stdout,"%s\n",tuple->N_2hop_addr.GetHostString());
      }
    }
    fprintf(stdout,"End of Routing-Links List.\n");
    fflush(stdout);
  }
#endif //UNIX
#endif //SIMULATE
}

void 
Nrlolsr::printTopology(int debuglvl){
  NbrTuple *tuple;
  if(olsrDebugValue>=debuglvl){
    DMSG(debuglvl,"== %s's topology table at time %f== \n",myaddress.GetHostString(),InlineGetCurrentTime());
    for(tuple=topologySet.PrintPeekInit();tuple!=NULL;tuple=topologySet.PrintPeekNext()){
      if(tuple!=NULL){
	DMSG(debuglvl,"T_Last=%s ",tuple->N_addr.GetHostString());
	DMSG(debuglvl,"T_dest=%s mssn=%d\n",tuple->N_2hop_addr.GetHostString(), tuple->seq_num);
      }
    }
    DMSG(debuglvl,"== end topo table ==\n");
  }
}


int 
Nrlolsr::checkCurrentTable(int callvalue){
  NbrTuple *nb,*nb2;
  int isgood;
  if(noerrors){
    for(nb=nbr_list.PrintPeekInit();nb!=NULL;nb=nbr_list.PrintPeekNext()){
      if(nb!=NULL){
	for(nb2=(nb->children).PrintPeekInit();nb2!=NULL;nb2=(nb->children).PrintPeekNext()){
	  if(nb2!=NULL){
	    isgood=0;
	    //check to see that this child points back up only once to parent
	    if((nb2->parents).FindObject(nb->N_addr)){
	      isgood++;
	    }
	    if((nb2->stepparents).FindObject(nb->N_addr)){
	      isgood++;
	    }
	    if(isgood==0){
	      DMSG(0,"table error from %d, child pointer with no return parents or stepparents pointer, step/parent is %s child is ",callvalue,nb->N_addr.GetHostString());
	      DMSG(0,"%s | ",nb2->N_addr.GetHostString());
	      noerrors=0;
	    }
	    if(isgood==2){
	      DMSG(0,"table error from %d, child pointer with stepparent and parent, step/parent is %s child is ",callvalue,nb->N_addr.GetHostString());
	      DMSG(0,"%s | ",nb2->N_addr.GetHostString());
	      noerrors=0;
	    }
	  }
	}
	for(nb2=(nb->parents).PrintPeekInit();nb2!=NULL;nb2=(nb->parents).PrintPeekNext()){
	  if(nb2!=NULL){
	    //check to see that parent points to child once
	    isgood=0;
	    if((nb2->children).FindObject(nb->N_addr)){
	      isgood++;
	    }
	    if(!isgood){
	      DMSG(0,"table error from %d, parent pointer with no return child pointer, parent %s child ",callvalue,nb2->N_addr.GetHostString());
	      DMSG(0,"%s found in checking table | ",nb->N_addr.GetHostString());
	      noerrors=0;
	    }
	  }
	}
	for(nb2=(nb->stepparents).PrintPeekInit();nb2!=NULL;nb2=(nb->stepparents).PrintPeekNext()){
	  if(nb2!=NULL){
	    //check to see that stepparents points to child once
	    isgood=0;
	    if((nb2->children).FindObject(nb->N_addr)){
	      isgood++;
	    }
	    if(!isgood){
	      DMSG(0,"table error from %d, stepparent pointer with no return child pointer, parent %s child ",callvalue,nb2->N_addr.GetHostString());
	      DMSG(0,"%s found in checking table | ",nb->N_addr.GetHostString());
	      noerrors=0;
	    }
	  }
	}
      }
    }
  }
  return 1;
}

void
Nrlolsr::printCurrentTable(int debuglvl){
  if(olsrDebugValue>=debuglvl){
    NbrTuple *nb,*nb2;
    DMSG(debuglvl," === nbr table at time %f === \n",InlineGetCurrentTime());
    for(nb=nbr_list.PrintPeekInit();nb!=NULL;nb=nbr_list.PrintPeekNext()){
      if(nb!=NULL){
	DMSG(debuglvl,":%dd %dh %dt %.2fk %s c(c",nb->N_delay,nb->hop,nb->N_status,nb->konectivity,nb->N_addr.GetHostString());
	for(nb2=(nb->children).PrintPeekInit();nb2!=NULL;nb2=(nb->children).PrintPeekNext()){
	  if(nb2!=NULL){
	    DMSG(debuglvl,"%s ",nb2->N_addr.GetHostString());
	  }
	}
	DMSG(debuglvl,")(p");
	for(nb2=(nb->parents).PrintPeekInit();nb2!=NULL;nb2=(nb->parents).PrintPeekNext()){
	  if(nb2!=NULL){
	    DMSG(3,"%s ",nb2->N_addr.GetHostString());
	  }
	}
	DMSG(debuglvl,")(d");
	for(nb2=(nb->stepparents).PrintPeekInit();nb2!=NULL;nb2=(nb->stepparents).PrintPeekNext()){
	  if(nb2!=NULL){
	    DMSG(debuglvl,"%s ",nb2->N_addr.GetHostString());
	  }
	}
	DMSG(debuglvl,")");
      }
    }
    DMSG(debuglvl,"\n");
    for(nb=nbr_2hop_list.PrintPeekInit();nb!=NULL;nb=nbr_2hop_list.PrintPeekNext()){
      if(nb!=NULL){
	if(nb->hop==2){
	  DMSG(debuglvl," %s(c",nb->N_addr.GetHostString());
	  for(nb2=(nb->children).PrintPeekInit();nb2!=NULL;nb2=(nb->children).PrintPeekNext()){
	    if(nb2!=NULL){
	      DMSG(debuglvl,"error%s ",nb2->N_addr.GetHostString());
	    }
	  }
	  DMSG(debuglvl,")(p");
	  for(nb2=(nb->parents).PrintPeekInit();nb2!=NULL;nb2=(nb->parents).PrintPeekNext()){
	    if(nb2!=NULL){
	      DMSG(debuglvl,"%s ",nb2->N_addr.GetHostString());
	    }
	  }
	  DMSG(debuglvl,")(s");
	  for(nb2=(nb->stepparents).PrintPeekInit();nb2!=NULL;nb2=(nb->stepparents).PrintPeekNext()){
	    if(nb2!=NULL){
	      DMSG(debuglvl,"%s ",nb2->N_addr.GetHostString());
	    }
	  }
	  DMSG(debuglvl,")");
	}
      }
    }
    DMSG(debuglvl,"\n ===end=== \n");
  }
}

// a bit convoluted because of the historisis  there are 2 checks in some areas to see
// which type of timeout is occuring historisis or complete timeout and removal
// if a historisis disconnect occurs it deleats 2 hop neighbors and makes it a lost neighbor
// the node will switch the lost_link to pending_link after sending out lost link message.
// checks each one hop neighbor and then checks all of there childrens timeout values
// if a one hop neighbor is removed all of its 2 hop links are also removed and it may be 
// deleated or moved to the 2 hop list if a valid link is still up
void
Nrlolsr::nb_purge() {
  //DMSG(6,"Enter: Nrlolsr::nb_purge()\n");
  NbrTuple *nb,*nbold=NULL, *children, *parents, *nb_top;
  int nbfree=0;
  int mprupdate=0;
  //int redoRoutes=0;// used when manually taking out topology tuples due to historisis 
  //DMSG(6,"Enter: nb_purge() for %s \n",myaddress.GetHostString());
  
  //printCurrentTable(3);
  for(nb=nbr_list.PeekInit();nb!=NULL;nb=nbr_list.PeekNext()){
    if(nb!=NULL){ // is a valid pointer
      //DMSG(8,"%f value of %s's historisis %f remove %f time\n",nb->konectivity,nb->N_addr.GetHostString(),T_down,nb->N_time);
      ////DMSG(1,"%f value of %d's historisis %f remove %f time\n",nb->konectivity,nb->N_addr,T_down,nb->N_time);
      if(nb->konectivity<T_down && (nb->N_status==SYM_LINKv4 || nb->N_status==MPR_LINKv4 || nb->N_status==ASYM_LINKv4)){ // check to see if historisis link failure occured
	nb->N_status=LOST_LINKv4;
	// must manually take out the topology tuple as they only time out based on timeout values
	nb_top=topologySet.FindObject(nb->N_addr,myaddress); // remove the forward link if in the topology table
	if(nb_top){
	  ////DMSG(1,"removing from %d topology tuple %d list at time %f due to historisis 1\n",myaddress.IPv4HostAddr(),nb_top->N_addr,CURRENT_TIME);
	  //DMSG(7,"Removing from %s topology tuple ",myaddress.GetHostString()); 
	  //DMSG(7,"%s list at time %f due to historisis 1\n",nb_top->N_addr.GetHostString(),InlineGetCurrentTime());
	  topologySet.RemoveCurrent();
	  delete nb_top;
	  //free(nb_top);
	  //redoRoutes=1;
	}
	nb_top=topologySet.FindObject(myaddress,nb->N_addr); // remove the reverse link if there
	if(nb_top){
	  //DMSG(7,"Removing from %s topology tuple ",myaddress.GetHostString());
	  //DMSG(7,"%s list at time %f due to historisis 2\n",nb_top->N_addr.GetHostString(),InlineGetCurrentTime());
	  ////DMSG(1,"removing from %d topology tuple %d list at time %f due to historisis 2\n",myaddress.IPv4HostAddr(),nb_top->N_addr,InlineGetCurrentTime());
	  topologySet.RemoveCurrent();
	  delete nb_top;
	  //free(nb_top);
	  //redoRoutes=1;
	}
      }
      if(nb->N_time<InlineGetCurrentTime() || nb->N_status==LOST_LINKv4){ //check to see if link expired b/c normal timeout
	mprupdate=1;
	fflush(stdout);
	if(nb->N_time<InlineGetCurrentTime()){ //get rid of one hop neighbor as well
	  ////DMSG(1,"removing nb %d from %d's list at time %f \n",nb->N_addr,myaddress.IPv4HostAddr(),InlineGetCurrentTime());
	  //DMSG(7,"Removing nb %s ",nb->N_addr.GetHostString());
	  //DMSG(7,"from %s's list at time %f cause %f timeout\n",myaddress.GetHostString(),InlineGetCurrentTime(),nb->N_time);
	  nbr_list.RemoveCurrent();
	}
	//removing children from parent/stepparent node that is being deleated
	for(children=(nb->children).PeekInit();children!=NULL;children=(nb->children).PeekNext()){
	  if(children!=NULL){
	    //abandon children
	    if((children->parents).FindObject(nb->N_addr)){
	      (children->parents).RemoveCurrent();
	    } else if((children->stepparents).FindObject(nb->N_addr)){
	      (children->stepparents).RemoveCurrent();
	    } else {
	      DMSG(0,"child without parent or stepparent pointer in nb_purge | ");
	    }
	    if((children->parents).IsEmpty()){
	      //child lost last parent, child runs free	      
	      ////DMSG(1,"removing 2 hop %d cause %d deleated from %d's 1 hop list (purge)\n",children->N_addr,nb->N_addr,myaddress.IPv4HostAddr());
	      // DMSG(7,"Removing 2 hop %s ",children->N_addr.GetHostString());
	      //DMSG(7,"cause %s deleated from ",nb->N_addr.GetHostString());
	      //DMSG(7,"%s's 1 hop list (purge)\n",myaddress.GetHostString());
	      if(nbr_2hop_list.FindObject(children->N_addr))
		nbr_2hop_list.RemoveCurrent();
	      if(!nbr_list.FindObject(children->N_addr)){ //check to see if it was exclusivly a 2 hop neighbor
		////DMSG(1,"testline 0 \n");
		//DMSG(12,"testline 0 \n");
		//get rid of step children
		for(parents=(children->children).PeekInit();parents!=NULL;parents=(children->children).PeekNext()){
		  if(parents!=NULL){
		    if((parents->stepparents).FindObject(children->N_addr)){
		      (parents->stepparents).RemoveCurrent();
		    } else if((parents->parents).FindObject(children->N_addr)){
		      DMSG(0,"parent pointer instead of stepparent pointer in nb_purge function | ");
		    } else {
		      DMSG(0,"missing stepparent pointer in nb_purge function | ");
		    }
		  }
		}
		(children->children).Clear();
		//get rid of step parents
		for(parents=(children->stepparents).PeekInit();parents!=NULL;parents=(children->stepparents).PeekNext()){
		  if(parents!=NULL){
		    //  //DMSG(8,"testline 3 \n");
		    //if(parents->N_addr!=nb->N_addr){
		    if(!(parents->N_addr.HostIsEqual((nb->N_addr)))){
		      //if(parents->children!=nb->children){
		      if((parents->children).FindObject(children->N_addr)){
			(parents->children).RemoveCurrent();
		      } else {
			DMSG(0,"missing child link in nb_purge function | ");
		      }
		      // }
		    }
		  }
		}
		(children->stepparents).Clear();
		delete children;
		//free(children);
	      } 	
	    }
  	  }
	}
	(nb->children).Clear();		
	if((nb->parents).IsEmpty()){ // checking to see if node has parents
	  if(nb->N_status!=LOST_LINKv4){ // if is not a lost link hold it for a bit then will remove later
	    nbold=nb;
	    nbfree=1;
	  }
	}
	else{
	  nb->hop=2; // is now a two hop neighbor 
	}
	NbrTuple *mprtuple;
	if((mprtuple = mprSelectorList.FindObject(nb->N_addr))){
	  mprSelectorList.RemoveCurrent();
	  delete mprtuple;
	  //free(mprtuple);
	  updateSM();
	}
      }
      else { // is a valid one hop neighbor check its children
	//check to see if children are missing
  	for(children=(nb->children).PeekInit();children!=NULL;children=(nb->children).PeekNext()){
  	  if(children!=NULL){
  	    if((nb->children).checkCurrent()){ // check to see if link expired child lost
  	      mprupdate=1;
	      //printCurrentTable(3);
	      ////DMSG(1,"%d's perspective deleating link %d from %d's table \n",myaddress.IPv4HostAddr(),children->N_addr,nb->N_addr);
	      //DMSG(7,"Removing: %s's perspective deleating link ",myaddress.GetHostString());
	      //DMSG(7,"%s ",children->N_addr.GetHostString());
	      //DMSG(7,"from %s's table \n",nb->N_addr.GetHostString());
	      (nb->children).RemoveCurrent();
	      if((children->parents).FindObject(nb->N_addr)) // child is lost
  		(children->parents).RemoveCurrent();
	      if((children->stepparents).FindObject(nb->N_addr)) 
		(children->stepparents).RemoveCurrent(); // (ah ha found you vindication!)
	      ////DMSG(1,"is empty? %d hop value %d",children->parents.IsEmpty(),children->hop);
	      //DMSG(9,"is empty? %d hop value %d",children->parents.IsEmpty(),children->hop);
	      if((children->parents).IsEmpty()){
  		//child is lost only parent
  		if(nbr_2hop_list.FindObject(children->N_addr)){ // may have not been added to two hop table????
		  nbr_2hop_list.RemoveCurrent();
		} else { 
		  //DMSG(8,"Warning: while removing two hop link %s which was not in 2 hop neighbor table\n",children->N_addr.GetHostString());
		}
		// remove all stepparent links 
		if(!nbr_list.FindObject(children->N_addr)){ //check to see if it was exclusivly a 2 hop neighbor
		  for(parents=((children->stepparents).PeekInit());parents!=NULL;parents=(children->stepparents).PeekNext()){
		    if(parents!=NULL){
		      if(!(parents->N_addr.HostIsEqual((nb->N_addr)))){ //don't remove current parent will be done later
			//if(parents->N_addr!=nb->N_addr){ //don't remove current parent will be done later
			if((parents->children).FindObject(children->N_addr))
			  (parents->children).RemoveCurrent();
		      }
		    }
		  }
		  (children->stepparents).Clear();		  
		  delete children;
		  //free(children);
		}
  	      }
  	    }
  	  }
  	}
      }
    }
    if(nbfree){
      //remove last of pointers to this object
      for(parents=(nbold->stepparents).PeekInit();parents!=NULL;parents=(nbold->stepparents).PeekNext()){
	if(parents!=NULL){
	  if((parents->children).FindObject(nbold->N_addr))
	    (parents->children).RemoveCurrent();
	}
      }
      (nbold->stepparents).Clear();
      delete nbold;
      //free(nbold);
      nbfree=0;
    }
  }
  if(nbfree){
    //remove last of pointers to this object
    for(parents=(nbold->stepparents).PeekInit();parents!=NULL;parents=(nbold->stepparents).PeekNext()){
      if(parents!=NULL){
	if((parents->children).FindObject(nbold->N_addr))
	  (parents->children).RemoveCurrent();
      }
    }
    (nbold->stepparents).Clear();
    delete nbold;
    //free(nbold);
  }

  // this is only done on the send hello function
  //  if(mprupdate)
  //  selectmpr();
  //printCurrentTable(3);
  //DMSG(6,"Exit: Nrlolsr::nb_purge()\n");
} //end nb_purge

void 
Nrlolsr::for_purge() {
  //DMSG(6,"Enter: Nrlolsr::for_purge()\n");
  NbrTuple *tuple;
  bool removedfor=true;
  for(tuple=forwardTable.PeekInit();tuple!=NULL && removedfor;tuple=forwardTable.PeekNext()) {
    if((tuple->N_time<InlineGetCurrentTime())){
       forwardTable.RemoveCurrent();
       delete tuple;
       //free(tuple);
    }
    else{
      removedfor=false;
    }
  }
  //DMSG(6,"Exit: Nrlolsr::for_purge()\n");
} // end for_purge

void 
Nrlolsr::dup_purge() {
  //DMSG(6,"Enter: Nrlolsr::dup_purge()\n");
  NbrTuple *tuple;
  bool removeddup=true;
  for(tuple=duplicateTable.PeekInit();tuple!=NULL && removeddup;tuple=duplicateTable.PeekNext()) {
    if((tuple->N_time<InlineGetCurrentTime())){
      //DMSG(7,"Removing duplicate tuple %s from ",tuple->N_addr.GetHostString());
      //DMSG(7,"%s's list at time %f \n",myaddress.IPv4HostAddr(),InlineGetCurrentTime());
      duplicateTable.RemoveCurrent();
      delete tuple;
      //free(tuple);
    }
    else{
      removeddup=false;
    }
  }
  //DMSG(6,"Exit: Nrlolsr::dup_purge()\n");
} // end dup_purge

void
Nrlolsr::hna_purge() {
  //DMSG(6,"Enter: Nrlolsr::hna_purge()\n");
  NbrTuple *tuple;
  bool removedhna = true;
  for(tuple=hnaSet.PeekInit();tuple!=NULL && removedhna;tuple=hnaSet.PeekNext()) {
    if((tuple->N_time<InlineGetCurrentTime())){
      hnaSet.RemoveCurrent();
      delete tuple;
      //free(tuple);
    } else {
      removedhna = false;
    }
  }
  //DMSG(6,"Exit: Nrlolsr::hna_purge()\n");
} // end hna_purge

// removes expired topology tuples if their timeout value is past the current time      
void
Nrlolsr::top_purge() {
  //DMSG(6,"Enter: Nrlolsr::top_purge()\n");
  // list is sorted by address not timeout value so have to check them all.
  NbrTuple *tuple;
  int one=1;
  int printtop=0;
  for(tuple=topologySet.PeekInit();tuple!=NULL;tuple=topologySet.PeekNext()) {
    if(tuple!=NULL){
      if((tuple->N_time2<InlineGetCurrentTime())){
	if(printtop){
	  one=0;
	  printtop=0;
	  //printTopology(3);
	}
	//DMSG(2,"removing from %s topology tuple ",myaddress.GetHostString());
	//DMSG(2,"%s at time %f %f was experation time\n",tuple->N_addr.GetHostString(),InlineGetCurrentTime(),tuple->N_time2);
	topologySet.RemoveCurrent();
	delete tuple;
	//free(tuple);
      } else {
	//DMSG(2,"not removing \n");
      }
    }
  }
  //DMSG(6,"Exit: Nrlolsr::top_purge()\n);
} // end top_purge

//mantissa time functions
UINT8 
Nrlolsr::doubletomantissa(double timeinseconds){
  //DMSG(6,"Enter: Nrlolsr::doubletomantissa(timeinseconds %d)\n",tieminseconds);
  int a, b;
  UINT8 mantissatime=0;
  for(b = 0;(double)timeinseconds/TIME_CONSTANT >= (double)pow(2,b);b++);//  fprintf(stdout,"%f first %f second\n",(double)timeinseconds/TIME_CONSTANT,(double)pow(2,b));
  b--;
  if(b<0){ //number was too small make smallest number possible
    a = 1;
    b = 0;
  } else if (b>15){ //number was too large make largest number possible
    a = 15;
    b = 15;
  } else { //everything is fine 
    a = (int)(16*((double)timeinseconds/(TIME_CONSTANT*(double)pow(2,b))-1));
    while(a>=16){
      a-=16;
      b++;
    }
  }
  mantissatime = a*16+b;
  //DMSG(6,"Exit: Nrlolsr::doubletomantissa(timeinseconds %d)\n",tieminseconds);
  return mantissatime;
}
  
double
Nrlolsr::mantissatodouble(UINT8 mantissatime){
  //DMSG(6,"Enter: Nrlolsr::mantissatodouble(mantissatime %d)\n",mantissatime);
  int a = mantissatime>>4;
  int b = mantissatime - a*16;
  double returntime = (double)(TIME_CONSTANT*(1+(double)a/16)*(double)pow(2,b));
  //DMSG(6,"Exit: Nrlolsr::mantissatodouble(mantissatime %d)\n",mantissatime);
  return returntime;
}

void 
Nrlolsr::Stop() 
{
  //DMSG(6,"Enter: Nrlolsr::Stop()\n");
  if(hello_timer.IsActive())  hello_timer.Deactivate();
  if(hello_jitter_timer.IsActive()) hello_jitter_timer.Deactivate();
  if(tc_timer.IsActive()) tc_timer.Deactivate();
  if(tc_jitter_timer.IsActive()) tc_jitter_timer.Deactivate();
  if(hna_timer.IsActive()) hna_timer.Deactivate();
  if(hna_jitter_timer.IsActive()) hna_jitter_timer.Deactivate();
  if(netBroadAddr.IsMulticast()){
    if(!socket.LeaveGroup(netBroadAddr,interfaceName)){
      DMSG(0,"Nrlolsr::Stop() Error leaving multicast group %s\n",netBroadAddr.GetHostString());
    }
  }
  socket.Close();

  // restore old routing table
  NbrTuple *tuple=routeTable.PeekInit();
  while(tuple){ //loop to clean extraQueue and remove old routes
    routeTable.RemoveCurrent();
    if(tuple->N_addr.HostIsEqual((tuple->N_2hop_addr))){
      //DMSG(7,"Removing direct route to %s\n",tuple->N_addr.GetHostString());
      if(!realRouteTable->DeleteRoute(tuple->N_addr,hostMaskLength,invalidAddress,interfaceIndex)){//,invalidAddress)){
	DMSG(0,"Nrlolsr::Stop() Error removing direct route to %s\n",tuple->N_addr.GetHostString());
      }
    } else {
      //DMSG(7,"Removing route to %s via ",tuple->N_addr.GetHostString());
      //DMSG(7,"%s\n",tuple->N_2hop_addr.GetHostString());
      if(!realRouteTable->DeleteRoute(tuple->N_addr,hostMaskLength,tuple->N_2hop_addr,interfaceIndex)){//,tuple->N_2hop_addr)){
	DMSG(0,"Nrlolsr::Stop() Error removing host route %s via ",tuple->N_addr.GetHostString());
	DMSG(0,"%s\n",tuple->N_2hop_addr.GetHostString());
      }
    }
    delete tuple;
    //free(tuple); 
    tuple=routeTable.PeekInit();
  }
  /* broadcast address no longer added or removed
  if(!netBroadAddr.IsMulticast()){
    //ProtoAddress gwAddr;
    //gwAddr.Init();
    if(!realRouteTable->DeleteRoute(netBroadAddr,broadMaskLength,invalidAddress,interfaceIndex)){//,gwAddr)){ 
      DMSG(0,"Nrlolsr::Stop() error deleting %s from routing table",netBroadAddr.GetHostString());
    }
  }
  */
  //  realRouteTable->SetRoutes(initialRouteTable);
  realRouteTable->Close();
#ifndef SIMULATE
#ifdef UNIX
  MPRSELPublishShutdown(handle_mprsel,0);
#endif //UNIX
#endif //SIMULATE
  CloseDebugLog();
  //DMSG(6,"Enter: Nrlolsr::Stop()\n");
} // end Nrlolsr::Stop()



