mesytec-mnode/external/taskflow-3.8.0/3rd-party/ff/distributed/ff_dreceiver.hpp
2025-01-04 01:25:05 +01:00

391 lines
13 KiB
C++

/* ***************************************************************************
*
* FastFlow is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License version 3 as
* published by the Free Software Foundation.
* Starting from version 3.0.1 FastFlow is dual licensed under the GNU LGPLv3
* or MIT License (https://github.com/ParaGroup/WindFlow/blob/vers3.x/LICENSE.MIT)
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
****************************************************************************
*/
/* Authors:
* Nicolo' Tonci
* Massimo Torquati
*/
#ifndef FF_DRECEIVER_H
#define FF_DRECEIVER_H
#include <iostream>
#include <sstream>
#include <ff/ff.hpp>
#include <ff/distributed/ff_network.hpp>
#include <ff/distributed/ff_dgroups.hpp>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <arpa/inet.h>
#include <cereal/cereal.hpp>
#include <cereal/archives/portable_binary.hpp>
#include <cereal/types/vector.hpp>
#include <cereal/types/polymorphic.hpp>
using namespace ff;
class ff_dreceiver: public ff_monode_t<message_t> {
protected:
std::map<int, ChannelType> sck2ChannelType;
/*static int sendRoutingTable(const int sck, const std::vector<int>& dest){
dataBuffer buff; std::ostream oss(&buff);
cereal::PortableBinaryOutputArchive oarchive(oss);
oarchive << dest;
size_t sz = htobe64(buff.getLen());
struct iovec iov[2];
iov[0].iov_base = &sz;
iov[0].iov_len = sizeof(sz);
iov[1].iov_base = buff.getPtr();
iov[1].iov_len = buff.getLen();
if (writevn(sck, iov, 2) < 0){
error("Error writing on socket the routing Table\n");
return -1;
}
return 0;
}*/
virtual int handshakeHandler(const int sck){
// ricevo l'handshake e mi salvo che tipo di connessione è
size_t size;
ChannelType t;
struct iovec iov[2];
iov[0].iov_base = &t; iov[0].iov_len = sizeof(ChannelType);
iov[1].iov_base = &size; iov[1].iov_len = sizeof(size);
switch (readvn(sck, iov, 2)) {
case -1: error("Error reading from socket\n"); // fatal error
case 0: return -1; // connection close
}
size = be64toh(size);
char groupName[size];
if (readn(sck, groupName, size) < 0){
error("Error reading from socket groupName\n"); return -1;
}
sck2ChannelType[sck] = t;
return 0; //this->sendRoutingTable(sck, reachableDestinations);
}
virtual void registerLogicalEOS(int sender){
for(size_t i = 0; i < this->get_num_outchannels(); i++)
ff_send_out_to(new message_t(sender, i), i);
}
virtual void registerEOS(int sck){
neos++;
}
virtual void forward(message_t* task, int){
if (task->chid == -1) ff_send_out(task);
else ff_send_out_to(task, this->routingTable[task->chid]); // assume the routing table is consistent WARNING!!!
}
virtual int handleBatch(int sck){
int requestSize;
switch(readn(sck, reinterpret_cast<char*>(&requestSize), sizeof(requestSize))) {
case -1: {
perror("readn");
error("Something went wrong in receiving the number of tasks!\n");
return -1;
} break;
case 0: return -1;
}
// always sending back the acknowledgement
if (writen(sck, reinterpret_cast<char*>(&ACK), sizeof(ack_t)) < 0){
if (errno != ECONNRESET && errno != EPIPE) {
error("Error sending back ACK to the sender (errno=%d)\n",errno);
return -1;
}
}
ChannelType t = sck2ChannelType[sck];
requestSize = ntohl(requestSize);
for(int i = 0; i < requestSize; i++)
if (handleRequest(sck, t)<0) return -1;
return 0;
}
virtual int handleRequest(int sck, ChannelType t){
int sender;
int chid;
size_t sz;
struct iovec iov[3];
iov[0].iov_base = &sender;
iov[0].iov_len = sizeof(sender);
iov[1].iov_base = &chid;
iov[1].iov_len = sizeof(chid);
iov[2].iov_base = &sz;
iov[2].iov_len = sizeof(sz);
switch (readvn(sck, iov, 3)) {
case -1: error("Error reading from socket errno=%d\n",errno); // fatal error
case 0: return -1; // connection close
}
// convert values to host byte order
sender = ntohl(sender);
chid = ntohl(chid);
sz = be64toh(sz);
if (sz > 0){
char* buff = new char [sz];
assert(buff);
if(readn(sck, buff, sz) < 0){
error("Error reading from socket in handleRequest\n");
delete [] buff;
return -1;
}
message_t* out = new message_t(buff, sz, true);
assert(out);
out->feedback = t == ChannelType::FBK;
out->sender = sender;
out->chid = chid;
this->forward(out, sck);
return 0;
}
//logical EOS
if (chid == -2){
registerLogicalEOS(sender);
return 0;
}
//pyshical EOS
registerEOS(sck);
return -1;
}
public:
ff_dreceiver(ff_endpoint acceptAddr, size_t input_channels, std::map<int, int> routingTable = {std::make_pair(0,0)}, int coreid=-1)
: input_channels(input_channels), acceptAddr(acceptAddr), routingTable(routingTable), coreid(coreid) {}
int svc_init() {
if (coreid!=-1)
ff_mapThreadToCpu(coreid);
#ifdef LOCAL
if ((listen_sck=socket(AF_LOCAL, SOCK_STREAM, 0)) < 0){
error("Error creating the socket\n");
return -1;
}
struct sockaddr_un serv_addr;
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sun_family = AF_LOCAL;
strncpy(serv_addr.sun_path, acceptAddr.address.c_str(), acceptAddr.address.size()+1);
#endif
#ifdef REMOTE
if ((listen_sck=socket(AF_INET, SOCK_STREAM, 0)) < 0){
error("Error creating the socket\n");
return -1;
}
int enable = 1;
// enable the reuse of the address
if (setsockopt(listen_sck, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0)
error("setsockopt(SO_REUSEADDR) failed\n");
struct sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY; // still listening from any interface
serv_addr.sin_port = htons( acceptAddr.port );
#endif
if (bind(listen_sck, (struct sockaddr*)&serv_addr,sizeof(serv_addr)) < 0){
error("Error binding\n");
return -1;
}
if (listen(listen_sck, MAXBACKLOG) < 0){
error("Error listening\n");
return -1;
}
return 0;
}
void svc_end() {
close(this->listen_sck);
#ifdef LOCAL
unlink(this->acceptAddr.address.c_str());
#endif
}
/*
Here i should not care of input type nor input data since they come from a socket listener.
Everything will be handled inside a while true in the body of this node where data is pulled from network
*/
message_t *svc(message_t* task) {
fd_set set, tmpset;
// intialize both sets (master, temp)
FD_ZERO(&set);
FD_ZERO(&tmpset);
// add the listen socket to the master set
FD_SET(this->listen_sck, &set);
// hold the greater descriptor
int fdmax = this->listen_sck;
while(neos < input_channels){
// copy the master set to the temporary
tmpset = set;
switch(select(fdmax+1, &tmpset, NULL, NULL, NULL)){
case -1: error("Error on selecting socket\n"); return EOS;
case 0: continue;
}
for(int idx=0; idx <= fdmax; idx++){
if (FD_ISSET(idx, &tmpset)){
if (idx == this->listen_sck) {
int connfd = accept(this->listen_sck, (struct sockaddr*)NULL ,NULL);
if (connfd == -1){
error("Error accepting client\n");
} else {
FD_SET(connfd, &set);
if(connfd > fdmax) fdmax = connfd;
this->handshakeHandler(connfd);
}
continue;
}
if (this->handleBatch(idx) < 0){
close(idx);
FD_CLR(idx, &set);
// update the maximum file descriptor
if (idx == fdmax)
for(int ii=(fdmax-1);ii>=0;--ii)
if (FD_ISSET(ii, &set)){
fdmax = ii;
break;
}
}
}
}
}
return this->EOS;
}
protected:
size_t neos = 0;
size_t input_channels;
int listen_sck;
ff_endpoint acceptAddr;
std::map<int, int> routingTable;
int coreid;
ack_t ACK;
};
class ff_dreceiverH : public ff_dreceiver {
//std::map<int, bool> isInternalConnection;
size_t internalNEos = 0, externalNEos = 0;
long next_rr_destination = 0;
void registerLogicalEOS(int sender){
for(size_t i = 0; i < this->get_num_outchannels()-1; i++)
ff_send_out_to(new message_t(sender, i), i);
}
void registerEOS(int sck){
neos++;
size_t internalConn = std::count_if(std::begin(sck2ChannelType),
std::end (sck2ChannelType),
[](std::pair<int, ChannelType> const &p) {return p.second == ChannelType::INT;});
if (sck2ChannelType[sck] != ChannelType::INT){
// logical EOS!!
/*for(int i = 0; i < this->get_num_outchannels()-1; i++)
ff_send_out(new message_t(0,0), i);*/
if (++externalNEos == (sck2ChannelType.size()-internalConn))
for(size_t i = 0; i < this->get_num_outchannels()-1; i++) ff_send_out_to(this->EOS, i);
} else{
/// logical EOS!
//ff_send_out_to(new message_t(0,0), this->get_num_outchannels()-1);
if (++internalNEos == internalConn)
ff_send_out_to(this->EOS, this->get_num_outchannels()-1);
}
}
/*virtual int handshakeHandler(const int sck){
size_t size;
struct iovec iov; iov.iov_base = &size; iov.iov_len = sizeof(size);
switch (readvn(sck, &iov, 1)) {
case -1: error("Error reading from socket\n"); // fatal error
case 0: return -1; // connection close
}
size = be64toh(size);
char groupName[size];
if (readn(sck, groupName, size) < 0){
error("Error reading from socket groupName\n"); return -1;
}
bool internalGroup = internalGroupsNames.contains(std::string(groupName,size));
isInternalConnection[sck] = internalGroup; // save somewhere the fact that this sck represent an internal connection
if (internalGroup) return this->sendRoutingTable(sck, internalDestinations);
std::vector<int> reachableDestinations;
for(const auto& [key, value] : this->routingTable) reachableDestinations.push_back(key);
return this->sendRoutingTable(sck, reachableDestinations);
}
*/
void forward(message_t* task, int sck){
if (sck2ChannelType[sck] == ChannelType::INT) ff_send_out_to(task, this->get_num_outchannels()-1);
else if (task->chid != -1) ff_send_out_to(task, this->routingTable[task->chid]);
else {
ff_send_out_to(task, next_rr_destination);
next_rr_destination = (next_rr_destination + 1) % (this->get_num_outchannels()-1);
}
}
public:
ff_dreceiverH(ff_endpoint acceptAddr, size_t input_channels, std::map<int, int> routingTable = {{0,0}}, int coreid=-1)
: ff_dreceiver(acceptAddr, input_channels, routingTable, coreid){
}
};
#endif