/***************************************************************************
* By Théophile Bastian, 2017
* M1 Network course project at ENS Cachan, Juliusz Chroboczek.
* License: WTFPL v2
**************************************************************************/
#include "neighbours.h"
#include "nw_constants.h"
#include
using namespace std;
Neighbours::Neighbours(Protocol* proto) :
proto(proto), lastPeerPeek(0)
{}
void Neighbours::fullCheck() {
for(auto nei : neiType) {
switch(nei.second) {
case NEI_SYM:
if(time(NULL) - lastRecv[nei.first] > csts::TIMEOUT_SYM_RECV
|| (time(NULL) - lastIHU[nei.first]
> csts::TIMEOUT_SYM_IHU))
{
changeNeiType(nei.first, NEI_POTENTIAL);
}
break;
case NEI_UNIDIR:
if(time(NULL) - lastRecv[nei.first] > csts::TIMEOUT_UNIDIR)
changeNeiType(nei.first, NEI_POTENTIAL);
break;
default:
break;
}
}
}
void Neighbours::fullUpdate() {
fullCheck();
for(auto nei : unidirNei)
updateSendPackets(nei, proto);
for(auto nei : symNei)
updateSendPackets(nei, proto);
if(potentialNei.size() > 0
&& symNei.size() < csts::SYM_COUNT_BEFORE_PEEK
&& time(NULL) - lastPeerPeek >= csts::TIME_PEER_PEEK) {
int nPeerId = rand() % potentialNei.size();
auto it = potentialNei.begin();
for(int at=0; at < nPeerId; ++at, ++it);
proto->sendEmpty(it->id);
lastPeerPeek = time(NULL);
}
}
void Neighbours::addPotentialNei(const Neighbour& nei) {
potentialNei.push_back(nei);
lastRecv.insert({nei.id, 0});
lastIHU.insert({nei.id, 0});
neiType.insert({nei.id, NEI_POTENTIAL});
proto->addIdAddr(nei.addr, nei.id);
}
void Neighbours::receivedFrom(u64 id) {
NeiType typ = neiType[id];
lastRecv.insert({id, time(NULL)});
if(typ == NEI_POTENTIAL)
changeNeiType(id, NEI_UNIDIR);
}
void Neighbours::hadIHU(u64 id) {
NeiType typ = neiType[id];
lastRecv.insert({id, time(NULL)});
lastIHU.insert({id, time(NULL)});
if(typ == NEI_POTENTIAL || typ == NEI_UNIDIR)
changeNeiType(id, NEI_SYM);
}
list& Neighbours::listOfType(NeiType typ) {
switch(typ) {
case NEI_POTENTIAL:
return potentialNei;
case NEI_UNIDIR:
return unidirNei;
case NEI_SYM:
return symNei;
default:
break;
}
throw WrongNeiType();
}
void Neighbours::changeNeiType(u64 id, NeiType nType) {
NeiType cType = neiType[id];
if(cType == nType)
return;
list& fromList = listOfType(cType), toList = listOfType(nType);
neiType.insert({id, nType});
bool wasSpliced=false;
for(auto it=fromList.begin(); it != fromList.end(); ++it) {
if(it->id == id) {
fromList.splice(it, toList);
wasSpliced=true;
break;
}
}
if(!wasSpliced) {
//TODO log error.
}
}
void Neighbours::updateSendPackets(const Neighbour& nei, Protocol* proto) {
if(time(NULL) - lastIHUSent[nei.id] >= csts::TIME_RESEND_IHU) {
lastIHUSent[nei.id] = time(NULL);
lastPckSent[nei.id] = time(NULL);
proto->sendIHU(nei.id);
}
else if(time(NULL) - lastPckSent[nei.id] >= csts::TIME_RESEND_EMPTY) {
lastPckSent[nei.id] = time(NULL);
proto->sendEmpty(nei.id);
}
}