WIP update

Finished moving Packet over to implicit sharing.
This commit is contained in:
attermann 2023-10-09 09:39:11 -06:00
parent 59b8e90d1f
commit 2c8006f3a9
5 changed files with 167 additions and 160 deletions

View File

@ -270,16 +270,16 @@ bool Destination::deregister_request_handler(const Bytes &path) {
void Destination::receive(const Packet &packet) { void Destination::receive(const Packet &packet) {
assert(_object); assert(_object);
if (packet._packet_type == Packet::LINKREQUEST) { if (packet.packet_type() == Packet::LINKREQUEST) {
Bytes plaintext(packet._data); Bytes plaintext(packet.data());
incoming_link_request(plaintext, packet); incoming_link_request(plaintext, packet);
} }
else { else {
// CBA TODO Why isn't the Packet decrypting itself? // CBA TODO Why isn't the Packet decrypting itself?
Bytes plaintext(decrypt(packet._data)); Bytes plaintext(decrypt(packet.data()));
extreme("Destination::receive: decrypted data: " + plaintext.toHex()); extreme("Destination::receive: decrypted data: " + plaintext.toHex());
if (plaintext) { if (plaintext) {
if (packet._packet_type == RNS::Packet::DATA) { if (packet.packet_type() == RNS::Packet::DATA) {
if (_object->_callbacks._packet) { if (_object->_callbacks._packet) {
try { try {
_object->_callbacks._packet(plaintext, packet); _object->_callbacks._packet(plaintext, packet);

View File

@ -190,13 +190,13 @@ bool Identity::validate(const Bytes &signature, const Bytes &message) {
void Identity::prove(const Packet &packet, const Destination &destination /*= Destination::NONE*/) { void Identity::prove(const Packet &packet, const Destination &destination /*= Destination::NONE*/) {
assert(_object); assert(_object);
Bytes signature(sign(packet._packet_hash)); Bytes signature(sign(packet.packet_hash()));
Bytes proof_data; Bytes proof_data;
if (RNS::Reticulum::should_use_implicit_proof()) { if (RNS::Reticulum::should_use_implicit_proof()) {
proof_data = signature; proof_data = signature;
} }
else { else {
proof_data = packet._packet_hash + signature; proof_data = packet.packet_hash() + signature;
} }
//zif (!destination) { //zif (!destination) {

View File

@ -18,25 +18,25 @@ Packet::Packet(const Destination &destination, const Interface &attached_interfa
} }
// following moved to object constructor to avoid extra NONE object // following moved to object constructor to avoid extra NONE object
//_destination = destination; //_destination = destination;
_header_type = header_type; _object->_header_type = header_type;
_packet_type = packet_type; _object->_packet_type = packet_type;
_transport_type = transport_type; _object->_transport_type = transport_type;
_context = context; _object->_context = context;
_transport_id = transport_id; _object->_transport_id = transport_id;
_data = data; _object->_data = data;
if (_data.size() > MDU) { if (_object->_data.size() > MDU) {
_truncated = true; _object->_truncated = true;
_data.resize(MDU); _object->_data.resize(MDU);
} }
_flags = get_packed_flags(); _object->_flags = get_packed_flags();
_create_receipt = create_receipt; _object->_create_receipt = create_receipt;
} }
else { else {
extreme("Creating packet without detination..."); extreme("Creating packet without detination...");
_raw = data; _object->_raw = data;
_packed = true; _object->_packed = true;
_fromPacked = true; _object->_fromPacked = true;
_create_receipt = false; _object->_create_receipt = false;
} }
extreme("Packet object created"); extreme("Packet object created");
} }
@ -47,21 +47,23 @@ Packet::~Packet() {
uint8_t Packet::get_packed_flags() { uint8_t Packet::get_packed_flags() {
assert(_object);
uint8_t packed_flags = 0; uint8_t packed_flags = 0;
if (_context == LRPROOF) { if (_object->_context == LRPROOF) {
packed_flags = (_header_type << 6) | (_transport_type << 4) | (Destination::LINK << 2) | _packet_type; packed_flags = (_object->_header_type << 6) | (_object->_transport_type << 4) | (Destination::LINK << 2) | _object->_packet_type;
} }
else { else {
packed_flags = (_header_type << 6) | (_transport_type << 4) | (_object->_destination.type() << 2) | _packet_type; packed_flags = (_object->_header_type << 6) | (_object->_transport_type << 4) | (_object->_destination.type() << 2) | _object->_packet_type;
} }
return packed_flags; return packed_flags;
} }
void Packet::unpack_flags(uint8_t flags) { void Packet::unpack_flags(uint8_t flags) {
_header_type = static_cast<header_types>((flags & 0b01000000) >> 6); assert(_object);
_transport_type = static_cast<Transport::types>((flags & 0b00110000) >> 4); _object->_header_type = static_cast<header_types>((flags & 0b01000000) >> 6);
_destination_type = static_cast<Destination::types>((flags & 0b00001100) >> 2); _object->_transport_type = static_cast<Transport::types>((flags & 0b00110000) >> 4);
_packet_type = static_cast<types>(flags & 0b00000011); _object->_destination_type = static_cast<Destination::types>((flags & 0b00001100) >> 2);
_object->_packet_type = static_cast<types>(flags & 0b00000011);
} }
@ -233,85 +235,85 @@ void Packet::pack() {
assert(_object); assert(_object);
debug("Packet::pack: packing packet..."); debug("Packet::pack: packing packet...");
_destination_hash = _object->_destination.hash(); _object->_destination_hash = _object->_destination.hash();
_raw.clear(); _object->_raw.clear();
_encrypted = false; _object->_encrypted = false;
_raw << _flags; _object->_raw << _object->_flags;
_raw << _hops; _object->_raw << _object->_hops;
if (_context == LRPROOF) { if (_object->_context == LRPROOF) {
debug("Packet::pack: destination link id: " + _object->_destination.link_id().toHex() ); debug("Packet::pack: destination link id: " + _object->_destination.link_id().toHex() );
_raw << _object->_destination.link_id(); _object->_raw << _object->_destination.link_id();
_raw << (uint8_t)_context; _object->_raw << (uint8_t)_object->_context;
_raw << _data; _object->_raw << _object->_data;
} }
else { else {
if (_header_type == HEADER_1) { if (_object->_header_type == HEADER_1) {
debug("Packet::pack: destination hash: " + _object->_destination.hash().toHex() ); debug("Packet::pack: destination hash: " + _object->_destination.hash().toHex() );
_raw << _object->_destination.hash(); _object->_raw << _object->_destination.hash();
_raw << (uint8_t)_context; _object->_raw << (uint8_t)_object->_context;
if (_packet_type == ANNOUNCE) { if (_object->_packet_type == ANNOUNCE) {
// Announce packets are not encrypted // Announce packets are not encrypted
_raw << _data; _object->_raw << _object->_data;
} }
else if (_packet_type == LINKREQUEST) { else if (_object->_packet_type == LINKREQUEST) {
// Link request packets are not encrypted // Link request packets are not encrypted
_raw << _data; _object->_raw << _object->_data;
} }
else if (_packet_type == PROOF && _context == RESOURCE_PRF) { else if (_object->_packet_type == PROOF && _object->_context == RESOURCE_PRF) {
// Resource proofs are not encrypted // Resource proofs are not encrypted
_raw << _data; _object->_raw << _object->_data;
} }
else if (_packet_type == PROOF && _object->_destination.type() == Destination::LINK) { else if (_object->_packet_type == PROOF && _object->_destination.type() == Destination::LINK) {
// Packet proofs over links are not encrypted // Packet proofs over links are not encrypted
_raw << _data; _object->_raw << _object->_data;
} }
else if (_context == RESOURCE) { else if (_object->_context == RESOURCE) {
// A resource takes care of encryption // A resource takes care of encryption
// by itself // by itself
_raw << _data; _object->_raw << _object->_data;
} }
else if (_context == KEEPALIVE) { else if (_object->_context == KEEPALIVE) {
// Keepalive packets contain no actual // Keepalive packets contain no actual
// data // data
_raw << _data; _object->_raw << _object->_data;
} }
else if (_context == CACHE_REQUEST) { else if (_object->_context == CACHE_REQUEST) {
// Cache-requests are not encrypted // Cache-requests are not encrypted
_raw << _data; _object->_raw << _object->_data;
} }
else { else {
// In all other cases, we encrypt the packet // In all other cases, we encrypt the packet
// with the destination's encryption method // with the destination's encryption method
_raw << _object->_destination.encrypt(_data); _object->_raw << _object->_destination.encrypt(_object->_data);
_encrypted = true; _object->_encrypted = true;
} }
} }
else if (_header_type == HEADER_2) { else if (_object->_header_type == HEADER_2) {
if (!_transport_id) { if (!_object->_transport_id) {
throw std::invalid_argument("Packet with header type 2 must have a transport ID"); throw std::invalid_argument("Packet with header type 2 must have a transport ID");
} }
debug("Packet::pack: transport id: " + _transport_id.toHex() ); debug("Packet::pack: transport id: " + _object->_transport_id.toHex() );
debug("Packet::pack: destination hash: " + _object->_destination.hash().toHex() ); debug("Packet::pack: destination hash: " + _object->_destination.hash().toHex() );
_raw << _transport_id; _object->_raw << _object->_transport_id;
_raw << _object->_destination.hash(); _object->_raw << _object->_destination.hash();
_raw << (uint8_t)_context; _object->_raw << (uint8_t)_object->_context;
if (_packet_type == ANNOUNCE) { if (_object->_packet_type == ANNOUNCE) {
// Announce packets are not encrypted // Announce packets are not encrypted
_raw << _data; _object->_raw << _object->_data;
} }
} }
} }
if (_raw.size() > _mtu) { if (_object->_raw.size() > _object->_mtu) {
throw std::length_error("Packet size of " + std::to_string(_raw.size()) + " exceeds MTU of " + std::to_string(_mtu) +" bytes"); throw std::length_error("Packet size of " + std::to_string(_object->_raw.size()) + " exceeds MTU of " + std::to_string(_object->_mtu) +" bytes");
} }
_packed = true; _object->_packed = true;
update_hash(); update_hash();
} }
@ -319,17 +321,17 @@ bool Packet::unpack() {
assert(_object); assert(_object);
debug("Packet::unpack: unpacking packet..."); debug("Packet::unpack: unpacking packet...");
try { try {
if (_raw.size() < Reticulum::HEADER_MINSIZE) { if (_object->_raw.size() < Reticulum::HEADER_MINSIZE) {
throw std::length_error("Packet size of " + std::to_string(_raw.size()) + " does not meet minimum header size of " + std::to_string(Reticulum::HEADER_MINSIZE) +" bytes"); throw std::length_error("Packet size of " + std::to_string(_object->_raw.size()) + " does not meet minimum header size of " + std::to_string(Reticulum::HEADER_MINSIZE) +" bytes");
} }
const uint8_t *raw = _raw.data(); const uint8_t *raw = _object->_raw.data();
// read header // read header
_flags = raw[0]; _object->_flags = raw[0];
_hops = raw[1]; _object->_hops = raw[1];
unpack_flags(_flags); unpack_flags(_object->_flags);
// CBA TODO detect invalid flags and throw error // CBA TODO detect invalid flags and throw error
if (false) { if (false) {
@ -337,27 +339,27 @@ bool Packet::unpack() {
return false; return false;
} }
if (_header_type == HEADER_2) { if (_object->_header_type == HEADER_2) {
if (_raw.size() < Reticulum::HEADER_MAXSIZE) { if (_object->_raw.size() < Reticulum::HEADER_MAXSIZE) {
throw std::length_error("Packet size of " + std::to_string(_raw.size()) + " does not meet minimum header size of " + std::to_string(Reticulum::HEADER_MAXSIZE) +" bytes"); throw std::length_error("Packet size of " + std::to_string(_object->_raw.size()) + " does not meet minimum header size of " + std::to_string(Reticulum::HEADER_MAXSIZE) +" bytes");
} }
_transport_id.assign(raw+2, Reticulum::DESTINATION_LENGTH); _object->_transport_id.assign(raw+2, Reticulum::DESTINATION_LENGTH);
_destination_hash.assign(raw+Reticulum::DESTINATION_LENGTH+2, Reticulum::DESTINATION_LENGTH); _object->_destination_hash.assign(raw+Reticulum::DESTINATION_LENGTH+2, Reticulum::DESTINATION_LENGTH);
_context = static_cast<context_types>(raw[2*Reticulum::DESTINATION_LENGTH+2]); _object->_context = static_cast<context_types>(raw[2*Reticulum::DESTINATION_LENGTH+2]);
_data.assign(raw+2*Reticulum::DESTINATION_LENGTH+3, _raw.size()-(2*Reticulum::DESTINATION_LENGTH+3)); _object->_data.assign(raw+2*Reticulum::DESTINATION_LENGTH+3, _object->_raw.size()-(2*Reticulum::DESTINATION_LENGTH+3));
// uknown at this point whether data is encrypted or not // uknown at this point whether data is encrypted or not
_encrypted = true; _object->_encrypted = true;
} }
else { else {
_transport_id.clear(); _object->_transport_id.clear();
_destination_hash.assign(raw+2, Reticulum::DESTINATION_LENGTH); _object->_destination_hash.assign(raw+2, Reticulum::DESTINATION_LENGTH);
_context = static_cast<context_types>(raw[Reticulum::DESTINATION_LENGTH+2]); _object->_context = static_cast<context_types>(raw[Reticulum::DESTINATION_LENGTH+2]);
_data.assign(raw+Reticulum::DESTINATION_LENGTH+3, _raw.size()-(Reticulum::DESTINATION_LENGTH+3)); _object->_data.assign(raw+Reticulum::DESTINATION_LENGTH+3, _object->_raw.size()-(Reticulum::DESTINATION_LENGTH+3));
// uknown at this point whether data is encrypted or not // uknown at this point whether data is encrypted or not
_encrypted = true; _object->_encrypted = true;
} }
_packed = false; _object->_packed = false;
update_hash(); update_hash();
} }
catch (std::exception& e) { catch (std::exception& e) {
@ -376,7 +378,7 @@ Sends the packet.
bool Packet::send() { bool Packet::send() {
assert(_object); assert(_object);
debug("Packet::send: sending packet..."); debug("Packet::send: sending packet...");
if (_sent) { if (_object->_sent) {
throw std::logic_error("Packet was already sent"); throw std::logic_error("Packet was already sent");
} }
/* /*
@ -392,7 +394,7 @@ bool Packet::send() {
} }
*/ */
if (!_packed) { if (!_object->_packed) {
pack(); pack();
} }
@ -404,7 +406,7 @@ bool Packet::send() {
} }
else { else {
error("No interfaces could process the outbound packet"); error("No interfaces could process the outbound packet");
_sent = false; _object->_sent = false;
//z_receipt = None; //z_receipt = None;
return false; return false;
} }
@ -418,7 +420,7 @@ Re-sends the packet.
bool Packet::resend() { bool Packet::resend() {
assert(_object); assert(_object);
debug("Packet::resend: re-sending packet..."); debug("Packet::resend: re-sending packet...");
if (!_sent) { if (!_object->_sent) {
throw std::logic_error("Packet was not sent yet"); throw std::logic_error("Packet was not sent yet");
} }
// Re-pack the packet to obtain new ciphertext for // Re-pack the packet to obtain new ciphertext for
@ -433,7 +435,7 @@ bool Packet::resend() {
} }
else { else {
error("No interfaces could process the outbound packet"); error("No interfaces could process the outbound packet");
_sent = false; _object->_sent = false;
//zself.receipt = None; //zself.receipt = None;
return false; return false;
} }
@ -441,7 +443,7 @@ bool Packet::resend() {
void Packet::update_hash() { void Packet::update_hash() {
assert(_object); assert(_object);
_packet_hash = get_hash(); _object->_packet_hash = get_hash();
} }
Bytes Packet::get_hash() { Bytes Packet::get_hash() {
@ -459,14 +461,14 @@ Bytes Packet::getTruncatedHash() {
Bytes Packet::get_hashable_part() { Bytes Packet::get_hashable_part() {
assert(_object); assert(_object);
Bytes hashable_part; Bytes hashable_part;
hashable_part << (uint8_t)(_raw.data()[0] & 0b00001111); hashable_part << (uint8_t)(_object->_raw.data()[0] & 0b00001111);
if (_header_type == Packet::HEADER_2) { if (_object->_header_type == Packet::HEADER_2) {
//hashable_part += self.raw[(RNS.Identity.TRUNCATED_HASHLENGTH//8)+2:] //hashable_part += self.raw[(RNS.Identity.TRUNCATED_HASHLENGTH//8)+2:]
hashable_part << _raw.mid((Identity::TRUNCATED_HASHLENGTH/8)+2); hashable_part << _object->_raw.mid((Identity::TRUNCATED_HASHLENGTH/8)+2);
} }
else { else {
//hashable_part += self.raw[2:]; //hashable_part += self.raw[2:];
hashable_part << _raw.mid(2); hashable_part << _object->_raw.mid(2);
} }
return hashable_part; return hashable_part;
} }
@ -479,32 +481,32 @@ Bytes Packet::get_hashable_part() {
std::string Packet::toString() { std::string Packet::toString() {
if (_packed) { if (_object->_packed) {
//unpack(); //unpack();
} }
std::string dump; std::string dump;
dump = "\n--------------------\n"; dump = "\n--------------------\n";
dump += "flags: " + hexFromByte(_flags) + "\n"; dump += "flags: " + hexFromByte(_object->_flags) + "\n";
dump += " header_type: " + std::to_string(_header_type) + "\n"; dump += " header_type: " + std::to_string(_object->_header_type) + "\n";
dump += " transport_type: " + std::to_string(_transport_type) + "\n"; dump += " transport_type: " + std::to_string(_object->_transport_type) + "\n";
dump += " destination_type: " + std::to_string(_destination_type) + "\n"; dump += " destination_type: " + std::to_string(_object->_destination_type) + "\n";
dump += " packet_type: " + std::to_string(_packet_type) + "\n"; dump += " packet_type: " + std::to_string(_object->_packet_type) + "\n";
dump += "hops: " + std::to_string(_hops) + "\n"; dump += "hops: " + std::to_string(_object->_hops) + "\n";
dump += "transport: " + _transport_id.toHex() + "\n"; dump += "transport: " + _object->_transport_id.toHex() + "\n";
dump += "destination: " + _destination_hash.toHex() + "\n"; dump += "destination: " + _object->_destination_hash.toHex() + "\n";
dump += "context_type: " + std::to_string(_header_type) + "\n"; dump += "context_type: " + std::to_string(_object->_header_type) + "\n";
dump += "data: " + _data.toHex() + "\n"; dump += "data: " + _object->_data.toHex() + "\n";
dump += " length: " + std::to_string(_data.size()) + "\n"; dump += " length: " + std::to_string(_object->_data.size()) + "\n";
dump += "raw: " + _raw.toHex() + "\n"; dump += "raw: " + _object->_raw.toHex() + "\n";
dump += " length: " + std::to_string(_raw.size()) + "\n"; dump += " length: " + std::to_string(_object->_raw.size()) + "\n";
if (_encrypted && _raw.size() > 0) { if (_object->_encrypted && _object->_raw.size() > 0) {
size_t header_len = Reticulum::HEADER_MINSIZE; size_t header_len = Reticulum::HEADER_MINSIZE;
if (_header_type == HEADER_2) { if (_object->_header_type == HEADER_2) {
header_len = Reticulum::HEADER_MAXSIZE; header_len = Reticulum::HEADER_MAXSIZE;
} }
dump += " header: " + _raw.left(header_len).toHex() + "\n"; dump += " header: " + _object->_raw.left(header_len).toHex() + "\n";
dump += " key: " + _raw.mid(header_len, Identity::KEYSIZE/8/2).toHex() + "\n"; dump += " key: " + _object->_raw.mid(header_len, Identity::KEYSIZE/8/2).toHex() + "\n";
Bytes ciphertext(_raw.mid(header_len+Identity::KEYSIZE/8/2)); Bytes ciphertext(_object->_raw.mid(header_len+Identity::KEYSIZE/8/2));
dump += " ciphertext: " + ciphertext.toHex() + "\n"; dump += " ciphertext: " + ciphertext.toHex() + "\n";
dump += " length: " + std::to_string(ciphertext.size()) + "\n"; dump += " length: " + std::to_string(ciphertext.size()) + "\n";
dump += " iv: " + ciphertext.left(16).toHex() + "\n"; dump += " iv: " + ciphertext.left(16).toHex() + "\n";

View File

@ -127,11 +127,28 @@ namespace RNS {
//zProofDestination &generate_proof_destination(); //zProofDestination &generate_proof_destination();
// getters/setters // getters/setters
inline const Interface& receiving_interface() const { assert(_object); return _object->_receiving_interface; } inline const Interface &receiving_interface() const { assert(_object); return _object->_receiving_interface; }
inline header_types header_type() const { assert(_object); return _object->_header_type; }
inline Transport::types transport_type() const { assert(_object); return _object->_transport_type; }
inline Destination::types destination_type() const { assert(_object); return _object->_destination_type; }
inline types packet_type() const { assert(_object); return _object->_packet_type; }
inline context_types context() const { assert(_object); return _object->_context; }
inline const Bytes &data() const { assert(_object); return _object->_data; }
inline const Bytes &raw() const { assert(_object); return _object->_raw; }
inline Bytes packet_hash() const { assert(_object); return _object->_packet_hash; }
std::string toString(); std::string toString();
private:
class Object {
public: public:
Object(const Destination &destination, const Interface &attached_interface) : _destination(destination), _attached_interface(attached_interface) {}
private:
Destination _destination;
Interface _attached_interface;
Interface _receiving_interface;
header_types _header_type = HEADER_1; header_types _header_type = HEADER_1;
Transport::types _transport_type = Transport::BROADCAST; Transport::types _transport_type = Transport::BROADCAST;
Destination::types _destination_type = Destination::SINGLE; Destination::types _destination_type = Destination::SINGLE;
@ -162,17 +179,6 @@ namespace RNS {
Bytes _raw; // header + ( plaintext | ciphertext-token ) Bytes _raw; // header + ( plaintext | ciphertext-token )
Bytes _data; // plaintext | ciphertext Bytes _data; // plaintext | ciphertext
private:
class Object {
public:
Object(const Destination &destination, const Interface &attached_interface) : _destination(destination), _attached_interface(attached_interface) {}
private:
Destination _destination;
Interface _attached_interface;
Interface _receiving_interface;
friend class Packet; friend class Packet;
}; };
std::shared_ptr<Object> _object; std::shared_ptr<Object> _object;

View File

@ -64,6 +64,13 @@ void setup() {
RNS::Destination destination(identity, RNS::Destination::IN, RNS::Destination::SINGLE, "test", "context"); RNS::Destination destination(identity, RNS::Destination::IN, RNS::Destination::SINGLE, "test", "context");
// 23.0% (+0.4%) // 23.0% (+0.4%)
destination.set_proof_strategy(RNS::Destination::PROVE_ALL);
//zannounce_handler = ExampleAnnounceHandler(
//z aspect_filter="example_utilities.announcesample.fruits";
//z)
//zRNS::Transport.register_announce_handler(announce_handler);
//destination.announce(RNS::bytesFromString(fruits[rand() % 7])); //destination.announce(RNS::bytesFromString(fruits[rand() % 7]));
// test path // test path
//destination.announce(RNS::bytesFromString(fruits[rand() % 7]), true, nullptr, RNS::bytesFromString("test_tag")); //destination.announce(RNS::bytesFromString(fruits[rand() % 7]), true, nullptr, RNS::bytesFromString("test_tag"));
@ -71,25 +78,17 @@ void setup() {
destination.announce(RNS::bytesFromString(fruits[rand() % 7])); destination.announce(RNS::bytesFromString(fruits[rand() % 7]));
// 23.9% (+0.8%) // 23.9% (+0.8%)
// test data send packet
RNS::Packet send_packet(destination, "The quick brown fox jumps over the lazy dog"); RNS::Packet send_packet(destination, "The quick brown fox jumps over the lazy dog");
send_packet.pack(); send_packet.pack();
RNS::extreme("Test send_packet packet: " + send_packet.toString()); RNS::extreme("Test send_packet packet: " + send_packet.toString());
// test packet receive // test data receive packet
RNS::Packet recv_packet(RNS::Destination::NONE, send_packet._raw); RNS::Packet recv_packet(RNS::Destination::NONE, send_packet.raw());
recv_packet.unpack(); recv_packet.unpack();
RNS::extreme("Test recv_packet packet: " + recv_packet.toString()); RNS::extreme("Test recv_packet packet: " + recv_packet.toString());
destination.receive(recv_packet); destination.receive(recv_packet);
//zdestination.set_proof_strategy(RNS::Destination::PROVE_ALL);
//zannounce_handler = ExampleAnnounceHandler(
//z aspect_filter="example_utilities.announcesample.fruits";
//z)
//zRNS::Transport.register_announce_handler(announce_handler);
} }
catch (std::exception& e) { catch (std::exception& e) {
RNS::error(std::string("!!! Exception in main: ") + e.what() + " !!!"); RNS::error(std::string("!!! Exception in main: ") + e.what() + " !!!");