/**
* Copyright (c) 2018 Cornell University.
*
* Author: Ted Yin <tederminant@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _SALTICIDAE_NETWORK_H
#define _SALTICIDAE_NETWORK_H
#include "salticidae/event.h"
#include "salticidae/netaddr.h"
#include "salticidae/msg.h"
#include "salticidae/conn.h"
namespace salticidae {
/** Network of nodes who can send async messages. */
template<typename MsgType>
class MsgNetwork: public ConnPool {
public:
class Conn: public ConnPool::Conn {
enum MsgState {
HEADER,
PAYLOAD
};
MsgType msg;
MsgState msg_state;
MsgNetwork *mn;
protected:
mutable size_t nsent;
mutable size_t nrecv;
public:
friend MsgNetwork;
Conn(MsgNetwork *mn): msg_state(HEADER), mn(mn), nsent(0), nrecv(0) {}
size_t get_nsent() const { return nsent; }
size_t get_nrecv() const { return nrecv; }
void clear_nsent() const { nsent = 0; }
void clear_nrecv() const { nrecv = 0; }
protected:
void on_read() override;
void on_setup() override {}
void on_teardown() override {}
};
using conn_t = RcObj<Conn>;
using msg_callback_t = std::function<void(const MsgType &msg, conn_t conn)>;
class msg_stat_by_opcode_t:
public std::unordered_map<typename MsgType::opcode_t,
std::pair<uint32_t, size_t>> {
public:
void add(const MsgType &msg) {
auto &p = this->operator[](msg.get_opcode());
p.first++;
p.second += msg.get_length();
}
};
private:
std::unordered_map<typename MsgType::opcode_t,
msg_callback_t> handler_map;
protected:
mutable msg_stat_by_opcode_t sent_by_opcode;
mutable msg_stat_by_opcode_t recv_by_opcode;
ConnPool::conn_t create_conn() override { return (new Conn(this))->self(); }
public:
MsgNetwork(const EventContext &eb,
int max_listen_backlog,
double try_conn_delay,
double conn_server_timeout,
size_t seg_buff_size):
ConnPool(eb, max_listen_backlog,
try_conn_delay,
conn_server_timeout,
seg_buff_size) {}
void reg_handler(typename MsgType::opcode_t opcode, msg_callback_t handler);
void send_msg(const MsgType &msg, conn_t conn);
using ConnPool::listen;
msg_stat_by_opcode_t &get_sent_by_opcode() const {
return sent_by_opcode;
}
msg_stat_by_opcode_t &get_recv_by_opcode() const {
return recv_by_opcode;
}
conn_t create_conn(const NetAddr &addr) {
return static_pointer_cast<Conn>(ConnPool::create_conn(addr));
}
};
/** Simple network that handles client-server requests. */
template<typename MsgType>
class ClientNetwork: public MsgNetwork<MsgType> {
using MsgNet = MsgNetwork<MsgType>;
std::unordered_map<NetAddr, typename MsgNet::conn_t> addr2conn;
public:
class Conn: public MsgNet::Conn {
ClientNetwork *cn;
pub