mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-01-03 11:51:10 -05:00
329050a9c2
Avoid problems to serialization on different platforms, without breaking nested STL containers serialization. The conversion have been made with sed, and checked with grep, plus kdiff3 visual ispection, plus rutime tests, so it should be fine.
579 lines
15 KiB
C++
579 lines
15 KiB
C++
/*******************************************************************************
|
|
* libretroshare/src/serialiser: rsserial.cc *
|
|
* *
|
|
* libretroshare: retroshare core library *
|
|
* *
|
|
* Copyright 2007-2008 by Robert Fernie <retroshare@lunamutt.com> *
|
|
* *
|
|
* 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 <https://www.gnu.org/licenses/>. *
|
|
* *
|
|
*******************************************************************************/
|
|
|
|
#include "serialiser/rsbaseserial.h"
|
|
|
|
#include "util/rsthreads.h"
|
|
#include "util/rsstring.h"
|
|
#include "util/rsprint.h"
|
|
|
|
#include "rsitems/rsitem.h"
|
|
#include "rsitems/itempriorities.h"
|
|
|
|
#include <math.h>
|
|
#include <map>
|
|
#include <vector>
|
|
#include <iostream>
|
|
#include <typeinfo>
|
|
|
|
|
|
/***
|
|
* #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 <sstream>
|
|
#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<int,Counter> 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<int,Counter>::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<RsItem*>(::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()
|
|
{
|
|
}
|
|
|
|
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)
|
|
{
|
|
_priority_level = QOS_PRIORITY_UNKNOWN ; // This value triggers PQIInterface to complain about undefined priorities
|
|
type = (ver << 24) + (service << 8) + subtype;
|
|
return;
|
|
}
|
|
|
|
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()
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
RsSerialiser::~RsSerialiser()
|
|
{
|
|
/* clean up the map */
|
|
std::map<uint32_t, RsSerialType *>::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<uint32_t, RsSerialType *>::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<uint32_t, RsSerialType *>::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<uint32_t, RsSerialType *>::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 > getRsPktMaxSize())
|
|
{
|
|
std::cerr << "(EE) trying to deserialise a packet with absurdely large size " << pkt_size << ". This means there's a bug upward or packet corruption. Packet content: " << RsUtil::BinToHex((unsigned char*)data,std::min(300u,pkt_size)) ;
|
|
return NULL ;
|
|
}
|
|
|
|
/* store the packet size to return the amount we should use up */
|
|
*size = pkt_size;
|
|
|
|
std::map<uint32_t, RsSerialType *>::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
|
|
std::cerr << "RsSerialiser::deserialise() ERROR Failed!";
|
|
std::cerr << std::endl;
|
|
std::cerr << "RsSerialiser::deserialise() pkt_size: " << pkt_size << " vs *size: " << *size;
|
|
std::cerr << std::endl;
|
|
|
|
//RsItem *item2 = (it->second)->deserialise(data, &pkt_size);
|
|
|
|
uint32_t failedtype = getRsItemId(data);
|
|
std::cerr << "RsSerialiser::deserialise() FAILED PACKET Size: ";
|
|
std::cerr << getRsItemSize(data) << " ID: ";
|
|
std::cerr << std::hex << failedtype << std::endl;
|
|
std::cerr << "RsSerialiser::deserialise() FAILED PACKET: ";
|
|
std::cerr << " Version: " << std::hex << (uint32_t) getRsItemVersion(failedtype) << std::dec;
|
|
std::cerr << " Class: " << std::hex << (uint32_t) getRsItemClass(failedtype) << std::dec;
|
|
std::cerr << " Type: " << std::hex << (uint32_t) getRsItemType(failedtype) << std::dec;
|
|
std::cerr << " SubType: " << std::hex << (uint32_t) getRsItemSubType(failedtype) << std::dec;
|
|
std::cerr << " Data: " << RsUtil::BinToHex((char*)data,pkt_size).substr(0,300) << std::endl;
|
|
std::cerr << std::endl;
|
|
#endif
|
|
return NULL;
|
|
}
|
|
|
|
if (pkt_size != *size)
|
|
{
|
|
#ifdef RSSERIAL_ERROR_DEBUG
|
|
std::cerr << "RsSerialiser::deserialise() ERROR: size mismatch!";
|
|
std::cerr << std::endl;
|
|
std::cerr << "RsSerialiser::deserialise() pkt_size: " << pkt_size << " vs *size: " << *size;
|
|
std::cerr << std::endl;
|
|
|
|
uint32_t failedtype = getRsItemId(data);
|
|
std::cerr << "RsSerialiser::deserialise() FAILED PACKET Size: ";
|
|
std::cerr << getRsItemSize(data) << " ID: ";
|
|
std::cerr << std::hex << failedtype << std::dec;
|
|
std::cerr << "RsSerialiser::deserialise() FAILED PACKET: ";
|
|
std::cerr << " Version: " << std::hex << (uint32_t) getRsItemVersion(failedtype) << std::dec;
|
|
std::cerr << " Class: " << std::hex << (uint32_t) getRsItemClass(failedtype) << std::dec;
|
|
std::cerr << " Type: " << std::hex << (uint32_t) getRsItemType(failedtype) << std::dec;
|
|
std::cerr << " SubType: " << std::hex << (uint32_t) getRsItemSubType(failedtype) << std::dec;
|
|
std::cerr << " Data: " << RsUtil::BinToHex((char*)data,pkt_size).substr(0,300) << std::endl;
|
|
std::cerr << 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)
|
|
{
|
|
printIndent(out, indent);
|
|
out << "RsItem: " << clsName << " ####################################";
|
|
out << std::endl;
|
|
return out;
|
|
}
|
|
|
|
std::ostream &printRsItemEnd(std::ostream &out, std::string clsName, uint16_t indent)
|
|
{
|
|
printIndent(out, indent);
|
|
out << "###################### " << clsName << " #####################";
|
|
out << std::endl;
|
|
return out;
|
|
}
|
|
|
|
std::ostream &RsRawItem::print(std::ostream &out, uint16_t indent)
|
|
{
|
|
printRsItemBase(out, "RsRawItem", indent);
|
|
printIndent(out, indent);
|
|
out << "Size: " << len << std::endl;
|
|
printRsItemEnd(out, "RsRawItem", indent);
|
|
return out;
|
|
}
|
|
|
|
|
|
uint32_t getRsPktMaxSize()
|
|
{
|
|
//return 65535; /* 2^16 (old artifical low size) */
|
|
//return 1048575; /* 2^20 -1 (Too Big! - must remove fixed static buffers first) */
|
|
/* Remember that every pqistreamer allocates an input buffer of this size!
|
|
* So don't make it too big!
|
|
*/
|
|
return 262143; /* 2^18 -1 */
|
|
}
|
|
|
|
|
|
uint32_t getRsPktBaseSize()
|
|
{
|
|
return 8; /* 4 + 4 */
|
|
}
|
|
|