Sends, floods and receives data

This commit is contained in:
Théophile Bastian 2016-11-26 19:17:56 +01:00
parent 98924f4ca6
commit 86c91f7488
10 changed files with 127 additions and 30 deletions

View file

@ -11,11 +11,7 @@
using namespace std; using namespace std;
ConfigFile::ConfigFile() { ConfigFile::ConfigFile() {
selfId=0; selfId = randId();
for(int i=0; i < 8; i++) {
selfId <<= 8;
selfId += rand() % 0xFF;
}
} }
bool ConfigFile::read(const char* path) { bool ConfigFile::read(const char* path) {
@ -44,7 +40,6 @@ bool ConfigFile::read(const char* path) {
addr.sin6_port = htons(port); addr.sin6_port = htons(port);
if(inet_pton(AF_INET6, addrStr.c_str(), &(addr.sin6_addr)) != 1) { if(inet_pton(AF_INET6, addrStr.c_str(), &(addr.sin6_addr)) != 1) {
//TODO proper log
fprintf(stderr, "Could not convert '%s' to IPv6 address\n", fprintf(stderr, "Could not convert '%s' to IPv6 address\n",
addrStr.c_str()); addrStr.c_str());
continue; continue;
@ -52,10 +47,27 @@ bool ConfigFile::read(const char* path) {
bootstrapNodes.push_back(Neighbour(id, addr)); bootstrapNodes.push_back(Neighbour(id, addr));
} }
else if(attr == "data") {
u64 id;
handle >> hex >> id >> dec;
if(id == 0)
id = randId();
string dataStr;
getline(handle, dataStr);
size_t nonWSPos = 0;
for(; nonWSPos < dataStr.size(); nonWSPos++)
if(dataStr[nonWSPos] != ' ' && dataStr[nonWSPos] != '\t')
break;
if(nonWSPos == dataStr.size())
continue;
data.push_back(make_pair(id, dataStr.substr(nonWSPos)));
}
else if(attr.empty()) else if(attr.empty())
continue; continue;
else { else {
//TODO proper log
fprintf(stderr, "Unknown configuration item: '%s'\n", fprintf(stderr, "Unknown configuration item: '%s'\n",
attr.c_str()); attr.c_str());
continue; continue;
@ -83,8 +95,22 @@ bool ConfigFile::write(const char* path) {
<< addr << ' ' << ntohs(nei.addr.sin6_port) << '\n'; << addr << ' ' << ntohs(nei.addr.sin6_port) << '\n';
} }
for(auto dat : data) {
handle << "data " << hex << dat.first << dec << " "
<< dat.second << '\n';
}
handle.close(); handle.close();
return true; return true;
} }
u64 ConfigFile::randId() const {
u64 out=0;
for(int i=0; i < 8; i++) {
out <<= 8;
out += rand() % 0xFF;
}
return out;
}

View file

@ -26,8 +26,16 @@ class ConfigFile {
}; };
/** Bootstrap nodes. No setter: wouldn't be useful. */ /** Bootstrap nodes. No setter: wouldn't be useful. */
const std::vector<std::pair<u64, std::string> >& getData() const {
return data;
}
/** Data to publish. */
private: private:
u64 randId() const;
u64 selfId; u64 selfId;
std::vector<Neighbour> bootstrapNodes; std::vector<Neighbour> bootstrapNodes;
std::vector<std::pair<u64, std::string> > data;
}; };

View file

@ -45,7 +45,6 @@ void DataStore::addData(Bytes pck, u32 seqno, u64 id, bool mine) {
timeEvents.push(TimeEvent( timeEvents.push(TimeEvent(
time(NULL) + csts::TIME_REPUBLISH_DATA, time(NULL) + csts::TIME_REPUBLISH_DATA,
seqno, id, EV_REPUBLISH)); seqno, id, EV_REPUBLISH));
} }
else { else {
timeEvents.push(TimeEvent( timeEvents.push(TimeEvent(

View file

@ -10,7 +10,6 @@ Flooder::Flooder(const Bytes& data, u64 datId, u32 seqno, Protocol* proto,
const std::list<Neighbour>& peers) : const std::list<Neighbour>& peers) :
data(data), datId(datId), seqno(seqno), proto(proto) data(data), datId(datId), seqno(seqno), proto(proto)
{ {
fprintf(stderr, "[DBG] Created flooder for %lX (%u)\n", datId, seqno);
for(auto it=peers.begin(); it != peers.end(); ++it) { for(auto it=peers.begin(); it != peers.end(); ++it) {
triesCount[it->id] = 0; triesCount[it->id] = 0;
toFlood.push(FloodEvt(time(NULL), it->id)); toFlood.push(FloodEvt(time(NULL), it->id));
@ -18,11 +17,23 @@ Flooder::Flooder(const Bytes& data, u64 datId, u32 seqno, Protocol* proto,
update(); update();
} }
Flooder::Flooder(const Bytes& data, u64 datId, u32 seqno, Protocol* proto,
u64 peer) :
data(data), datId(datId), seqno(seqno), proto(proto)
{
addPeer(peer);
update();
}
Flooder::~Flooder() {
}
void Flooder::update() { void Flooder::update() {
while(!toFlood.empty()) { while(!toFlood.empty()) {
const FloodEvt& evt = toFlood.top(); const FloodEvt& evt = toFlood.top();
if(evt.time > time(NULL)) if(evt.time > time(NULL)) {
break; break;
}
toFlood.pop(); toFlood.pop();
if(triesCount[evt.id] > csts::FLOOD_RETRIES) { if(triesCount[evt.id] > csts::FLOOD_RETRIES) {
@ -31,7 +42,6 @@ void Flooder::update() {
continue; continue;
} }
else if(triesCount[evt.id] < 0) { else if(triesCount[evt.id] < 0) {
fprintf(stderr, "[DBG] Got your IHave, %lX!\n", evt.id);
continue; // IHave received continue; // IHave received
} }
@ -48,6 +58,11 @@ void Flooder::gotIHave(u64 id, u32 withSeqno) {
triesCount[id] = -1; triesCount[id] = -1;
} }
void Flooder::addPeer(u64 peer) {
triesCount[peer] = 0;
toFlood.push(FloodEvt(time(NULL), peer));
}
void Flooder::sendTo(u64 id) { void Flooder::sendTo(u64 id) {
proto->sendData(id, data, seqno, datId); proto->sendData(id, data, seqno, datId);
} }

View file

@ -18,6 +18,9 @@ class Flooder {
public: public:
Flooder(const Bytes& data, u64 datId, u32 seqno, Protocol* proto, Flooder(const Bytes& data, u64 datId, u32 seqno, Protocol* proto,
const std::list<Neighbour>& peers); const std::list<Neighbour>& peers);
Flooder(const Bytes& data, u64 datId, u32 seqno, Protocol* proto,
u64 peer);
~Flooder();
void update(); void update();
/** Call often enough (ie ~1s) */ /** Call often enough (ie ~1s) */
@ -25,6 +28,9 @@ class Flooder {
void gotIHave(u64 id, u32 withSeqno); void gotIHave(u64 id, u32 withSeqno);
/** Acknoledges the reception of the resource by peer `id`. */ /** Acknoledges the reception of the resource by peer `id`. */
void addPeer(u64 peer);
/** Notifies that a new peer must be flooded. */
bool done() const { return toFlood.empty(); } bool done() const { return toFlood.empty(); }
private: //meth private: //meth

View file

@ -16,6 +16,9 @@
#include <cstdlib> #include <cstdlib>
#include <ctime> #include <ctime>
#include <unistd.h> #include <unistd.h>
#include <signal.h>
bool terminate=false;
int main(int argc, char** argv) { int main(int argc, char** argv) {
bool hasConfig = false; bool hasConfig = false;
@ -27,6 +30,8 @@ int main(int argc, char** argv) {
srand(time(NULL)+42); srand(time(NULL)+42);
signal(SIGINT, [](int) { terminate = true; });
ConfigFile cfg; ConfigFile cfg;
if(hasConfig) { if(hasConfig) {
if(!cfg.read(configFilePath) || !cfg.write(configFilePath)) { if(!cfg.read(configFilePath) || !cfg.write(configFilePath)) {
@ -40,24 +45,33 @@ int main(int argc, char** argv) {
addr.sin6_family = AF_INET6; addr.sin6_family = AF_INET6;
addr.sin6_port = htons(csts::DEFAULT_PORT); addr.sin6_port = htons(csts::DEFAULT_PORT);
printf("%lX\n", cfg.getSelfId()); fprintf(stderr, "[INFO] Starting with ID %lX\n", cfg.getSelfId());
Protocol proto(addr, cfg.getSelfId()); Protocol proto(addr, cfg.getSelfId());
DataStore dataStore(&proto); DataStore dataStore(&proto);
for(auto dat : cfg.getData()) {
Bytes pck;
pck << csts::TLV_DATA_TEXT << (u8)dat.second.size();
for(u8 chr : dat.second)
pck << chr;
dataStore.addData(pck, time(NULL), dat.first, true);
fprintf(stderr, "[INFO] Adding data `%s`\n", dat.second.c_str());
}
Neighbours neighboursManager(&proto, &dataStore); Neighbours neighboursManager(&proto, &dataStore);
for(const Neighbour& nei : cfg.getBootstrapNodes()) { for(const Neighbour& nei : cfg.getBootstrapNodes()) {
char addr[54]; char addr[54];
inet_ntop(AF_INET6, &nei.addr.sin6_addr, addr, 54); inet_ntop(AF_INET6, &nei.addr.sin6_addr, addr, 54);
printf("Neigh: %lX [%s]:%hu\n", nei.id, addr, fprintf(stderr, "[INFO] Bootstrap neighbour: %lX [%s]:%hu\n",
ntohs(nei.addr.sin6_port)); nei.id, addr, ntohs(nei.addr.sin6_port));
neighboursManager.addPotentialNei(nei); neighboursManager.addPotentialNei(nei);
} }
PacketParser pckParser(&neighboursManager, &proto, &dataStore); PacketParser pckParser(&neighboursManager, &proto, &dataStore);
while(true) { while(!terminate) {
neighboursManager.fullUpdate(); neighboursManager.fullUpdate();
while(proto.readyRead()) { while(proto.readyRead()) {

View file

@ -15,6 +15,12 @@ Neighbours::Neighbours(Protocol* proto, DataStore* dataStore) :
proto(proto), dataStore(dataStore), lastPeerPeek(0), lastSentNR(0) proto(proto), dataStore(dataStore), lastPeerPeek(0), lastSentNR(0)
{} {}
Neighbours::~Neighbours() {
for(auto fl : dataFlooder) {
delete fl.second;
}
}
void Neighbours::fullCheck() { void Neighbours::fullCheck() {
for(auto nei : neiType) { for(auto nei : neiType) {
switch(nei.second) { switch(nei.second) {
@ -66,17 +72,19 @@ void Neighbours::fullUpdate() {
for(auto flooder=dataFlooder.begin(); flooder != dataFlooder.end(); ) for(auto flooder=dataFlooder.begin(); flooder != dataFlooder.end(); )
{ {
if(flooder->second.done()) if(flooder->second->done()) {
delete flooder->second;
flooder = dataFlooder.erase(flooder); flooder = dataFlooder.erase(flooder);
}
else { else {
flooder->second.update(); flooder->second->update();
++flooder; ++flooder;
} }
} }
for(u64 datId : dataStore->toFlood()) { for(u64 datId : dataStore->toFlood()) {
dataFlooder.insert({datId, dataFlooder.insert({datId,
Flooder( new Flooder(
(*dataStore)[datId], datId, dataStore->getSeqno(datId), (*dataStore)[datId], datId, dataStore->getSeqno(datId),
proto, symNei)}); proto, symNei)});
dataStore->setFlooded(datId); dataStore->setFlooded(datId);
@ -154,7 +162,7 @@ list<Neighbour>* Neighbours::listOfType(NeiType typ) {
void Neighbours::gotIHave(u64 from, u64 datId, u32 seqno) { void Neighbours::gotIHave(u64 from, u64 datId, u32 seqno) {
if(dataFlooder.find(datId) != dataFlooder.end()) { if(dataFlooder.find(datId) != dataFlooder.end()) {
dataFlooder.at(datId).gotIHave(from, seqno); dataFlooder.at(datId)->gotIHave(from, seqno);
} }
} }
@ -177,6 +185,11 @@ void Neighbours::changeNeiType(u64 id, NeiType nType) {
} }
if(!wasSpliced) { if(!wasSpliced) {
fprintf(stderr, "[ERROR] Node %lX wasn't found (type change)\n", id); fprintf(stderr, "[ERROR] Node %lX wasn't found (type change)\n", id);
return;
}
if(nType == NEI_SYM) {
floodTo(id);
} }
} }
@ -211,3 +224,19 @@ list<Neighbour>::iterator Neighbours::randPeer(list<Neighbour>* list) {
return it; return it;
} }
void Neighbours::floodTo(u64 peer) {
vector<u64> datIds;
dataStore->ids(datIds);
for(u64 datId : datIds) {
auto curFlooder = dataFlooder.find(datId);
if(curFlooder != dataFlooder.end() && !curFlooder->second->done()) {
curFlooder->second->addPeer(peer);
}
else {
dataFlooder.insert({datId, new Flooder(
(*dataStore)[datId], datId,
dataStore->getSeqno(datId), proto, peer)});
}
}
}

View file

@ -18,6 +18,7 @@
class Neighbours { class Neighbours {
public: public:
Neighbours(Protocol* proto, DataStore* dataStore); Neighbours(Protocol* proto, DataStore* dataStore);
~Neighbours();
void fullCheck(); void fullCheck();
/** Cleans the peers lists by removing the expired entries. */ /** Cleans the peers lists by removing the expired entries. */
@ -65,6 +66,8 @@ class Neighbours {
bool sendIHU(u64 id); bool sendIHU(u64 id);
std::list<Neighbour>::iterator randPeer(std::list<Neighbour>* list); std::list<Neighbour>::iterator randPeer(std::list<Neighbour>* list);
void floodTo(u64 peer);
private: private:
Protocol* proto; Protocol* proto;
DataStore* dataStore; DataStore* dataStore;
@ -72,7 +75,7 @@ class Neighbours {
std::unordered_map<u64, time_t> lastRecv, lastIHU; std::unordered_map<u64, time_t> lastRecv, lastIHU;
std::unordered_map<u64, time_t> lastPckSent, lastIHUSent; std::unordered_map<u64, time_t> lastPckSent, lastIHUSent;
std::unordered_map<u64, NeiType> neiType; std::unordered_map<u64, NeiType> neiType;
std::unordered_map<u64, Flooder> dataFlooder; std::unordered_map<u64, Flooder*> dataFlooder;
time_t lastPeerPeek, lastSentNR; time_t lastPeerPeek, lastSentNR;
}; };

View file

@ -26,7 +26,7 @@ void PacketParser::readTLV(Bytes& pck, u64 nei, const SockAddr& addr) {
u8 type, len; u8 type, len;
pck >> type >> len; pck >> type >> len;
printf("[INFO] Analyzing %d\n", type); fprintf(stderr, "[INFO] Parsing %d from %lX.\n", type, nei);
if(pck.size() < len) { if(pck.size() < len) {
fprintf(stderr, "[WARNING] Advertised TLV does not fit in the packet" fprintf(stderr, "[WARNING] Advertised TLV does not fit in the packet"

View file

@ -27,7 +27,6 @@ Protocol::Protocol(const SockAddr& listenAddr, u64 selfId) :
} }
// Set socket reception timeout // Set socket reception timeout
/*
struct timeval tv; struct timeval tv;
tv.tv_sec = 0; tv.tv_sec = 0;
tv.tv_usec = 100000; tv.tv_usec = 100000;
@ -35,7 +34,6 @@ Protocol::Protocol(const SockAddr& listenAddr, u64 selfId) :
perror("Cannot set socket timeout"); perror("Cannot set socket timeout");
throw NwError(); throw NwError();
} }
*/
startPollNetwork(); startPollNetwork();
} }
@ -71,18 +69,17 @@ void Protocol::sendBody(const Bytes& body, const SockAddr& to) {
Bytes pck; Bytes pck;
pck << csts::MAGIC << csts::VERSION << (u16)body.size() << selfId pck << csts::MAGIC << csts::VERSION << (u16)body.size() << selfId
<< body; << body;
//TODO check size < MTU
char buffer[MAX_MTU]; char buffer[MAX_MTU];
pck.writeToBuffer(buffer, MAX_MTU); pck.writeToBuffer(buffer, MAX_MTU);
ssize_t rc = ssize_t rc =
sendto(sock, buffer, pck.size(), 0, (struct sockaddr*)&to, sizeof(to)); sendto(sock, buffer, pck.size(), 0, (struct sockaddr*)&to, sizeof(to));
if(rc != (ssize_t)pck.size()) { if(rc != (ssize_t)pck.size()) {
//TODO log warning. fprintf(stderr, "[WARNING] Whole packet not sent\n");
} }
fprintf(stderr, "[INFO] sending packet [%d] to port %hu\n",
body.size() > 0 ? body[0] : -1, ntohs(to.sin6_port));
} }
void Protocol::sendBody(const Bytes& body, const u64& id) { void Protocol::sendBody(const Bytes& body, const u64& id) {
fprintf(stderr, "[INFO] sending packet [%d] to %lX\n",
body.size() > 0 ? body[0] : -1, id);
return sendBody(body, addrOfId(id)); return sendBody(body, addrOfId(id));
} }
@ -169,10 +166,12 @@ void Protocol::pollNetwork() {
ssize_t readDat = recvfrom(sock, buffer, MAX_MTU, 0, ssize_t readDat = recvfrom(sock, buffer, MAX_MTU, 0,
&fromAddr, &fromAddrLen); &fromAddr, &fromAddrLen);
if(readDat < 0) { if(readDat < 0) {
if(errno == 11) // Socket timeout - expected behaviour
continue;
perror("[WARNING] Bad packet"); perror("[WARNING] Bad packet");
continue; continue;
} }
if(readDat <= 0) { if(readDat == 0) {
fprintf(stderr, "[WARNING] Empty packet.\n"); fprintf(stderr, "[WARNING] Empty packet.\n");
continue; continue;
} }
@ -209,8 +208,6 @@ void Protocol::pollNetwork() {
continue; continue;
} }
fprintf(stderr, "[INFO] Received packet [%d]\n",
data.size() > 8 ? data[8] : -1);
AvailPacket pck; AvailPacket pck;
pck.from = convFromAddr; pck.from = convFromAddr;
pck.data = data; pck.data = data;