Add protocol
This commit is contained in:
parent
e5857f842d
commit
2b03969aa4
2 changed files with 300 additions and 0 deletions
212
protocol.cpp
Normal file
212
protocol.cpp
Normal file
|
@ -0,0 +1,212 @@
|
|||
/***************************************************************************
|
||||
* By Théophile Bastian, 2017
|
||||
* M1 Network course project at ENS Cachan, Juliusz Chroboczek.
|
||||
* License: WTFPL v2 <http://www.wtfpl.net/>
|
||||
**************************************************************************/
|
||||
|
||||
#include "protocol.h"
|
||||
#include <cstring>
|
||||
|
||||
using namespace std;
|
||||
|
||||
const size_t MAX_MTU = (1 << 16) + 42;
|
||||
|
||||
Protocol::Protocol(const SockAddr& listenAddr, u64 selfId) :
|
||||
sock(socket(PF_INET6, SOCK_DGRAM, 0)), listenAddr(listenAddr),
|
||||
selfId(selfId), terminating(false)
|
||||
{
|
||||
if(bind(sock, (struct sockaddr*)(&listenAddr), sizeof(listenAddr)) != 0) {
|
||||
perror("Cannot bind socket");
|
||||
throw NwError();
|
||||
}
|
||||
|
||||
// Set socket reception timeout
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 100000;
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
|
||||
perror("Cannot set socket timeout");
|
||||
throw NwError();
|
||||
}
|
||||
|
||||
startPollNetwork();
|
||||
}
|
||||
|
||||
Protocol::~Protocol() {
|
||||
terminating = true;
|
||||
pollThread.join();
|
||||
}
|
||||
|
||||
void Protocol::addIdAddr(const SockAddr& addr, u64 id) {
|
||||
addrMap.insert({id, addr});
|
||||
}
|
||||
|
||||
bool Protocol::readyRead() const {
|
||||
return !availPackets.empty();
|
||||
}
|
||||
|
||||
Bytes Protocol::getPacket(SockAddr* from) {
|
||||
if(!readyRead())
|
||||
return Bytes();
|
||||
AvailPacket pck;
|
||||
{
|
||||
lock_guard<mutex>(this->availPacketsMutex);
|
||||
pck = availPackets.front();
|
||||
availPackets.pop();
|
||||
}
|
||||
if(from != NULL)
|
||||
*from = pck.from;
|
||||
return pck.data;
|
||||
}
|
||||
|
||||
void Protocol::sendBody(const Bytes& body, const SockAddr& to) {
|
||||
Bytes pck;
|
||||
pck << csts::MAGIC << csts::VERSION << (u16)body.size() << selfId
|
||||
<< body;
|
||||
//TODO check size < MTU
|
||||
char buffer[MAX_MTU];
|
||||
pck.writeToBuffer(buffer, MAX_MTU);
|
||||
ssize_t rc =
|
||||
sendto(sock, buffer, pck.size(), 0, (struct sockaddr*)&to, sizeof(to));
|
||||
if(rc != (ssize_t)pck.size()) {
|
||||
//TODO log warning.
|
||||
}
|
||||
}
|
||||
void Protocol::sendBody(const Bytes& body, const u64& id) {
|
||||
return sendBody(body, addrOfId(id));
|
||||
}
|
||||
|
||||
void Protocol::sendEmpty(const SockAddr& to) {
|
||||
sendBody(Bytes(), to);
|
||||
}
|
||||
void Protocol::sendEmpty(u64 to) {
|
||||
sendEmpty(addrOfId(to));
|
||||
}
|
||||
|
||||
void Protocol::sendIHU(const SockAddr& to, u64 id) {
|
||||
Bytes pck;
|
||||
pck << csts::TLV_IHU << (u8) 8 << id;
|
||||
sendBody(pck, to);
|
||||
}
|
||||
void Protocol::sendIHU(u64 id) {
|
||||
sendIHU(addrOfId(id), id);
|
||||
}
|
||||
|
||||
void Protocol::sendNReq(const SockAddr& to) {
|
||||
Bytes pck;
|
||||
pck << csts::TLV_NR << (u8) 0;
|
||||
sendBody(pck, to);
|
||||
}
|
||||
void Protocol::sendNReq(u64 id) {
|
||||
sendNReq(addrOfId(id));
|
||||
}
|
||||
|
||||
void Protocol::sendNeighbours(const SockAddr& to,
|
||||
const std::vector<Neighbour>& neigh) {
|
||||
Bytes pck;
|
||||
u8 len = neigh.size() * (8+16+2);
|
||||
pck << csts::TLV_NEIGH << len;
|
||||
for(const Neighbour& nei : neigh) {
|
||||
u8 addr[16];
|
||||
memcpy(addr, nei.addr.sin6_addr.s6_addr, 16);
|
||||
pck << nei.id;
|
||||
for(int b=0; b < 16; b++)
|
||||
pck << addr[b];
|
||||
pck << (u16)nei.addr.sin6_port;
|
||||
}
|
||||
|
||||
sendBody(pck, to);
|
||||
}
|
||||
void Protocol::sendNeighbours(u64 id, const std::vector<Neighbour>& neigh) {
|
||||
sendNeighbours(addrOfId(id), neigh);
|
||||
}
|
||||
|
||||
void Protocol::sendIHave(const SockAddr& to, u64 datId, u32 seqno) {
|
||||
Bytes pck;
|
||||
pck << csts::TLV_IHAVE << (u8) 12 << seqno << datId;
|
||||
sendBody(pck, to);
|
||||
}
|
||||
|
||||
void Protocol::sendIHave(u64 id, u64 datId, u32 seqno) {
|
||||
sendIHave(addrOfId(id), datId, seqno);
|
||||
}
|
||||
|
||||
void Protocol::startPollNetwork() {
|
||||
pollThread = std::thread([this] { this->pollNetwork(); });
|
||||
}
|
||||
|
||||
void Protocol::pollNetwork() {
|
||||
u8 buffer[MAX_MTU];
|
||||
SockAddr fromAddr6;
|
||||
struct sockaddr* fromAddr = (struct sockaddr*)&fromAddr6;
|
||||
socklen_t fromAddrLen;
|
||||
while(!terminating) {
|
||||
//TODO is it blocking?
|
||||
ssize_t readDat = recvfrom(sock, buffer, MAX_MTU, 0,
|
||||
fromAddr, &fromAddrLen);
|
||||
if(readDat < 0) {
|
||||
perror("Warning: could not read from socket");
|
||||
continue;
|
||||
}
|
||||
else if(readDat == 0)
|
||||
continue;
|
||||
Bytes data(buffer, readDat);
|
||||
u8 magic, version;
|
||||
data >> magic >> version;
|
||||
if(magic != csts::MAGIC) {
|
||||
//TODO log
|
||||
continue;
|
||||
}
|
||||
if(version != csts::VERSION) {
|
||||
//TODO log
|
||||
continue;
|
||||
}
|
||||
u16 bodyLen;
|
||||
data >> bodyLen;
|
||||
if(data.size() < bodyLen + 64u) {
|
||||
//TODO log bad length
|
||||
continue;
|
||||
}
|
||||
else if(data.size() != bodyLen + 64u) {
|
||||
//TODO log warning bad length
|
||||
}
|
||||
|
||||
SockAddr convFromAddr;
|
||||
if(fromAddr->sa_family == AF_INET)
|
||||
convFromAddr = addrOfV4(*(struct sockaddr_in*)fromAddr);
|
||||
else if(fromAddr->sa_family == AF_INET6)
|
||||
convFromAddr = *(SockAddr*)fromAddr;
|
||||
else {
|
||||
fprintf(stderr, "ERROR: Unknown address family.");
|
||||
continue;
|
||||
}
|
||||
|
||||
AvailPacket pck;
|
||||
pck.from = convFromAddr;
|
||||
pck.data = data;
|
||||
{
|
||||
lock_guard<mutex>(this->availPacketsMutex);
|
||||
availPackets.push(pck);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const SockAddr& Protocol::addrOfId(u64 id) {
|
||||
try {
|
||||
return addrMap.at(id);
|
||||
} catch(std::out_of_range& e) {
|
||||
throw UnknownId(id);
|
||||
}
|
||||
}
|
||||
|
||||
SockAddr Protocol::addrOfV4(const sockaddr_in& addrv4) {
|
||||
SockAddr out;
|
||||
memset(&out, 0, sizeof(SockAddr));
|
||||
out.sin6_family = AF_INET6;
|
||||
out.sin6_port = addrv4.sin_port;
|
||||
char addr6[17];
|
||||
inet_pton(AF_INET6, "::ffff:0:0", addr6);
|
||||
memcpy(addr6 + 12, &addrv4.sin_addr.s_addr, 4);
|
||||
return out;
|
||||
}
|
||||
|
88
protocol.h
Normal file
88
protocol.h
Normal file
|
@ -0,0 +1,88 @@
|
|||
/***************************************************************************
|
||||
* By Théophile Bastian, 2017
|
||||
* M1 Network course project at ENS Cachan, Juliusz Chroboczek.
|
||||
* License: WTFPL v2 <http://www.wtfpl.net/>
|
||||
**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
#include "nw_constants.h"
|
||||
#include "Bytes.h"
|
||||
|
||||
class Protocol {
|
||||
public:
|
||||
class NwError : public std::exception {};
|
||||
class ThreadError : public std::exception {};
|
||||
class UnknownId : public std::exception {
|
||||
public:
|
||||
UnknownId(u64 id) : _id(id) {}
|
||||
u64 id() const { return _id; }
|
||||
private:
|
||||
u64 _id;
|
||||
};
|
||||
|
||||
Protocol(const SockAddr& dest, u64 selfId);
|
||||
~Protocol();
|
||||
|
||||
void addIdAddr(const sockaddr_in6& addr, u64 id);
|
||||
|
||||
bool readyRead() const;
|
||||
/** Returns whether a packet is available. */
|
||||
|
||||
Bytes getPacket(SockAddr* from);
|
||||
/** Appends the body of a full packet to `out`. */
|
||||
|
||||
void sendBody(const Bytes& body, const SockAddr& to);
|
||||
void sendBody(const Bytes& body, const u64& id);
|
||||
/** Sends the given `body` (wrapped in headers) */
|
||||
|
||||
void sendEmpty(const SockAddr& to);
|
||||
void sendEmpty(u64 to);
|
||||
|
||||
void sendIHU(const SockAddr& to, u64 id);
|
||||
void sendIHU(u64 id);
|
||||
/** Sends a IHU packet */
|
||||
|
||||
void sendNReq(const SockAddr& to);
|
||||
void sendNReq(u64 id);
|
||||
/** Sends a neighbour request packet */
|
||||
|
||||
void sendNeighbours(const SockAddr& to,
|
||||
const std::vector<Neighbour>& neigh);
|
||||
void sendNeighbours(u64 id,
|
||||
const std::vector<Neighbour>& neigh);
|
||||
/** Sends a neighbours list packet */
|
||||
|
||||
void sendIHave(const SockAddr& to, u64 datId, u32 seqno);
|
||||
void sendIHave(u64 id, u64 datId, u32 seqno);
|
||||
/** Sends a IHave packet for `datId` */
|
||||
|
||||
private: //meth
|
||||
void startPollNetwork();
|
||||
void pollNetwork();
|
||||
const SockAddr& addrOfId(u64 id);
|
||||
SockAddr addrOfV4(const sockaddr_in& addrv4);
|
||||
|
||||
private:
|
||||
struct AvailPacket {
|
||||
SockAddr from;
|
||||
Bytes data;
|
||||
};
|
||||
|
||||
int sock;
|
||||
SockAddr listenAddr;
|
||||
u64 selfId;
|
||||
bool terminating;
|
||||
|
||||
std::thread pollThread;
|
||||
std::mutex availPacketsMutex;
|
||||
std::queue<AvailPacket> availPackets;
|
||||
std::unordered_map<u64, SockAddr> addrMap;
|
||||
};
|
||||
|
Loading…
Reference in a new issue