/******************************************************************************* * libretroshare/src/serialiser: rsserial.cc * * * * libretroshare: retroshare core library * * * * Copyright (C) 2007-2008 Robert Fernie * * Copyright (C) 2021 Gioacchino Mazzurco * * Copyright (C) 2021 AsociaciĆ³n Civil Altermundi * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * * published by the Free Software Foundation, either version 3 of the * * License, or (at your option) any later version. * * * * 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, see . * * * *******************************************************************************/ #include #include #include #include #include #include "serialiser/rsbaseserial.h" #include "util/cxx23retrocompat.h" #include "util/rsthreads.h" #include "util/rsstring.h" #include "util/rsprint.h" #include "rsitems/rsitem.h" #include "rsitems/itempriorities.h" /*** * #define RSSERIAL_DEBUG 1 * #define RSSERIAL_ERROR_DEBUG 1 ***/ // As these represent SERIOUS ERRORs, this debug should be left one. #define RSSERIAL_ERROR_DEBUG 1 #if defined(RSSERIAL_DEBUG) || defined(RSSERIAL_ERROR_DEBUG) #include #endif RsItem::RsItem(uint32_t t) :type(t) { _priority_level = QOS_PRIORITY_UNKNOWN ; // This value triggers PQIInterface to complain about undefined priorities } #ifdef DO_STATISTICS class Counter { public: Counter(int i): _i(i) {} Counter(): _i(0) {} int v() const { return _i ; } int& v() { return _i ; } private: int _i ; }; static RsMutex smtx ; static std::map size_hits ; static int nb_rsitem_creations = 0 ; static int total_rsitem_mallocs = 0 ; static int total_rsitem_frees = 0 ; static int total_rsitem_freed = 0 ; static rstime_t last_time = 0 ; void *RsItem::operator new(size_t s) { // std::cerr << "New RsItem: s=" << s << std::endl; RsStackMutex m(smtx) ; ++size_hits[ s ].v() ; rstime_t now = time(NULL); ++nb_rsitem_creations ; total_rsitem_mallocs += s ; if(last_time + 20 < now) { std::cerr << "Memory statistics:" << std::endl; std::cerr << " Total RsItem memory: " << total_rsitem_mallocs << std::endl; std::cerr << " Total RsItem creations: " << nb_rsitem_creations << std::endl; std::cerr << " Total RsItem freed memory: " << total_rsitem_freed << std::endl; std::cerr << " Total RsItem deletions: " << total_rsitem_frees << std::endl; std::cerr << "Now printing histogram:" << std::endl; for(std::map::const_iterator it(size_hits.begin());it!=size_hits.end();++it) std::cerr << it->first << " " << it->second.v() << std::endl; last_time = now ; } RsItem *a = static_cast(::operator new(s)) ; return a ; } void RsItem::operator delete(void *p,size_t s) { // std::cerr << "Delete RsItem: s=" << s << std::endl; RsStackMutex m(smtx) ; total_rsitem_freed += s ; ++total_rsitem_frees ; ::operator delete(p) ; } #endif RsItem::RsItem(uint8_t ver, uint8_t cls, uint8_t t, uint8_t subtype) { _priority_level = QOS_PRIORITY_UNKNOWN ; // This value triggers PQIInterface to complain about undefined priorities type = (ver << 24) + (cls << 16) + (t << 8) + subtype; } RsItem::~RsItem() = default; void RsItem::print_string(std::string &out, uint16_t indent) { std::ostringstream stream; print(stream, indent); out += stream.str(); } uint32_t RsItem::PacketId() const { return type; } uint8_t RsItem::PacketVersion() { return (type >> 24); } uint8_t RsItem::PacketClass() { return (type >> 16) & 0xFF; } uint8_t RsItem::PacketType() { return (type >> 8) & 0xFF; } uint8_t RsItem::PacketSubType() const { return (type & 0xFF); } /* For Service Packets */ RsItem::RsItem(uint8_t ver, uint16_t service, uint8_t subtype) { // This value triggers PQIInterface to complain about undefined priorities _priority_level = QOS_PRIORITY_UNKNOWN; type = (ver << 24) + (service << 8) + subtype; } RsItem::RsItem( uint8_t ver, RsServiceType service, uint8_t subtype, RsItemPriority prio ): type(static_cast( (ver << 24) + (std::to_underlying(service) << 8) + subtype )), _priority_level(prio) {} uint16_t RsItem::PacketService() const { return (type >> 8) & 0xFFFF; } void RsItem::setPacketService(uint16_t service) { type &= 0xFF0000FF; type |= (uint32_t) (service << 8); } RsSerialType::RsSerialType(uint32_t t) :type(t & 0xFFFFFF00) { return; } RsSerialType::RsSerialType(uint8_t ver, uint8_t cls, uint8_t t) { type = (ver << 24) + (cls << 16) + (t << 8); return; } RsSerialType::RsSerialType(uint8_t ver, uint16_t service) { type = (ver << 24) + (service << 8); return; } RsSerialType::~RsSerialType() { return; } uint32_t RsSerialType::size(RsItem *) { #ifdef RSSERIAL_DEBUG std::cerr << "RsSerialType::size()" << std::endl; #endif /* base size: type + length */ return 8; } bool RsSerialType::serialise(RsItem */*item*/, void */*data*/, uint32_t */*size*/) { std::cerr << "(EE) Empty method called for missing serialize() method in serializer class " << typeid(this).name() << std::endl; #ifdef RSSERIAL_DEBUG std::cerr << "RsSerialType::serialise()" << std::endl; #endif return false; } RsItem * RsSerialType::deserialise(void */*data*/, uint32_t */*size*/) { #ifdef RSSERIAL_DEBUG std::cerr << "RsSerialType::deserialise()" << std::endl; #endif return NULL; } uint32_t RsSerialType::PacketId() const { return type; } RsSerialiser::RsSerialiser() = default; RsSerialiser::~RsSerialiser() { /* clean up the map */ std::map::iterator it; for(it = serialisers.begin(); it != serialisers.end(); ++it) { delete (it->second); } serialisers.clear(); return; } bool RsSerialiser::addSerialType(RsSerialType *serialiser) { uint32_t type = (serialiser->PacketId() & 0xFFFFFF00); std::map::iterator it; if (serialisers.end() != (it = serialisers.find(type))) { #ifdef RSSERIAL_DEBUG std::cerr << "RsSerialiser::addSerialType() Error Serialiser already exists!"; std::cerr << std::endl; #endif return false; } serialisers[type] = serialiser; return true; } uint32_t RsSerialiser::size(RsItem *item) { /* find the type */ uint32_t type = (item->PacketId() & 0xFFFFFF00); std::map::iterator it; if (serialisers.end() == (it = serialisers.find(type))) { /* remove 8 more bits -> try again */ type &= 0xFFFF0000; if (serialisers.end() == (it = serialisers.find(type))) { /* one more try */ type &= 0xFF000000; if (serialisers.end() == (it = serialisers.find(type))) { #ifdef RSSERIAL_ERROR_DEBUG std::cerr << "RsSerialiser::size() ERROR serialiser missing!" << std::endl; std::string out; rs_sprintf(out, "%x", item->PacketId()); std::cerr << "RsSerialiser::size() PacketId: "; std::cerr << out; std::cerr << std::endl; #endif return 0; } } } #ifdef RSSERIAL_DEBUG std::string out; rs_sprintf(out, "RsSerialiser::size() Item->PacketId(): %x matched to Serialiser Type: %lu", item->PacketId(), type); std::cerr << out << std::endl; #endif return (it->second)->size(item); } bool RsSerialiser::serialise (RsItem *item, void *data, uint32_t *size) { /* find the type */ uint32_t type = (item->PacketId() & 0xFFFFFF00); std::map::iterator it; if (serialisers.end() == (it = serialisers.find(type))) { /* remove 8 more bits -> try again */ type &= 0xFFFF0000; if (serialisers.end() == (it = serialisers.find(type))) { /* one more try */ type &= 0xFF000000; if (serialisers.end() == (it = serialisers.find(type))) { #ifdef RSSERIAL_ERROR_DEBUG std::cerr << "RsSerialiser::serialise() ERROR serialiser missing!"; std::string out; rs_sprintf(out, "%x", item->PacketId()); std::cerr << "RsSerialiser::serialise() PacketId: "; std::cerr << out; std::cerr << std::endl; #endif return false; } } } #ifdef RSSERIAL_DEBUG std::string out; rs_sprintf(out, "RsSerialiser::serialise() Item->PacketId(): %x matched to Serialiser Type: %lu", item->PacketId(), type); std::cerr << out << std::endl; #endif return (it->second)->serialise(item, data, size); } RsItem * RsSerialiser::deserialise(void *data, uint32_t *size) { /* find the type */ if (*size < 8) { #ifdef RSSERIAL_ERROR_DEBUG std::cerr << "RsSerialiser::deserialise() ERROR Not Enough Data(1)"; std::cerr << std::endl; #endif return NULL; } uint32_t type = (getRsItemId(data) & 0xFFFFFF00); uint32_t pkt_size = getRsItemSize(data); //std::cerr << "RsSerialiser::deserialise() RsItem Type: " << std::hex << getRsItemId(data) << " Size: " << pkt_size; //std::cerr << std::endl; if (pkt_size > *size) { #ifdef RSSERIAL_ERROR_DEBUG std::cerr << "RsSerialiser::deserialise() ERROR Size mismatch(2)"; std::cerr << std::endl; #endif return NULL; } if(pkt_size > RsSerialiser::MAX_SERIAL_SIZE) { RS_ERR("Attempt to deserialise a packet with absurdely large size ") << pkt_size << ". This means there's a bug upward or packet " << "corruption. Packet content: " << hexDump(data, std::min(300u,pkt_size)); return nullptr; } /* store the packet size to return the amount we should use up */ *size = pkt_size; std::map::iterator it; if (serialisers.end() == (it = serialisers.find(type))) { /* remove 8 more bits -> try again */ type &= 0xFFFF0000; if (serialisers.end() == (it = serialisers.find(type))) { /* one more try */ type &= 0xFF000000; if (serialisers.end() == (it = serialisers.find(type))) { #ifdef RSSERIAL_ERROR_DEBUG std::cerr << "RsSerialiser::deserialise() ERROR deserialiser missing!"; std::string out; rs_sprintf(out, "%x", getRsItemId(data)); std::cerr << "RsSerialiser::deserialise() PacketId: "; std::cerr << out << std::endl; #endif return NULL; } } } RsItem *item = (it->second)->deserialise(data, &pkt_size); if (!item) { #ifdef RSSERIAL_ERROR_DEBUG uint32_t failedtype = getRsItemId(data); RS_ERR("Failed!") << std::endl << "pkt_size: " << pkt_size << " vs *size: " << *size << std::endl << std::hex << "Size: " << getRsItemSize(data) << " ID: " << failedtype << std::endl << " Version: " << (uint32_t) getRsItemVersion(failedtype) << " Class: " << (uint32_t) getRsItemClass(failedtype) << " Type: " << (uint32_t) getRsItemType(failedtype) << " SubType: " << (uint32_t) getRsItemSubType(failedtype) << " Data: " << hexDump(data, std::min(pkt_size, 300)) << std::dec << std::endl; #endif return nullptr; } #ifdef RSSERIAL_ERROR_DEBUG if(pkt_size != *size) { uint32_t failedtype = getRsItemId(data); RS_ERR("size mismatch!") << std::endl << "pkt_size: " << pkt_size << " vs *size: " << *size << std::endl << "FAILED PACKET Size: " << getRsItemSize(data) << std::hex << " ID: " << failedtype << " Version: " << (uint32_t) getRsItemVersion(failedtype) << " Class: " << (uint32_t) getRsItemClass(failedtype) << " Type: " << (uint32_t) getRsItemType(failedtype) << " SubType: " << (uint32_t) getRsItemSubType(failedtype) << " Data: " << hexDump(data, std::min(pkt_size ,300)) << std::endl; } #endif return item; } bool setRsItemHeader(void *data, uint32_t size, uint32_t type, uint32_t pktsize) { if (size < 8) return false; uint32_t offset = 0; bool ok = true; ok &= setRawUInt32(data, 8, &offset, type); ok &= setRawUInt32(data, 8, &offset, pktsize); return ok; } uint32_t getRsItemId(void *data) { uint32_t type = 0; uint32_t offset = 0; getRawUInt32(data, 4, &offset, &type); return type; } uint32_t getRsItemSize(void *data) { uint32_t size = 0; uint32_t offset = 4; getRawUInt32(data, 8, &offset, &size); return size; } uint8_t getRsItemVersion(uint32_t type) { return (type >> 24); } uint8_t getRsItemClass(uint32_t type) { return (type >> 16) & 0xFF; } uint8_t getRsItemType(uint32_t type) { return (type >> 8) & 0xFF; } uint8_t getRsItemSubType(uint32_t type) { return (type & 0xFF); } uint16_t getRsItemService(uint32_t type) { return (type >> 8) & 0xFFFF; } std::ostream &printRsItemBase(std::ostream &out, std::string clsName, uint16_t indent) { #ifndef RS_DISABLE_DEPRECATED_DEBUG_UTILS printIndent(out, indent); out << "RsItem: " << clsName << " ####################################"; out << std::endl; #endif return out; } std::ostream &printRsItemEnd(std::ostream &out, std::string clsName, uint16_t indent) { #ifndef RS_DISABLE_DEPRECATED_DEBUG_UTILS printIndent(out, indent); out << "###################### " << clsName << " #####################"; out << std::endl; #endif return out; } std::ostream &RsRawItem::print(std::ostream &out, uint16_t indent) { #ifndef RS_DISABLE_DEPRECATED_DEBUG_UTILS printRsItemBase(out, "RsRawItem", indent); printIndent(out, indent); out << "Size: " << len << std::endl; printRsItemEnd(out, "RsRawItem", indent); #endif return out; } uint32_t getRsPktMaxSize() { return RsSerialiser::MAX_SERIAL_SIZE; } uint32_t getRsPktBaseSize() { return 8; /* 4 + 4 */ }