/******************************************************************************* * libretroshare/src/serialiser: rsserializer.cc * * * * libretroshare: retroshare core library * * * * Copyright (C) 2016 Cyril Soler * * Copyright (C) 2020 Gioacchino Mazzurco * * Copyright (C) 2020 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 "rsitems/rsitem.h" #include "util/rsprint.h" #include "serialiser/rsserializer.h" #include "serialiser/rstypeserializer.h" #include "util/stacktrace.h" #include "util/rsdebug.h" RsItem *RsServiceSerializer::deserialise(void *data, uint32_t *size) { if(!data || !size || *size < 8) { RsErr() << __PRETTY_FUNCTION__ << " Called with inconsistent parameters data: " << std::endl; if(data) RsErr() << "Data is: " << hexDump(data, std::min(50u,*size)) << ((*size>50)?"...":"") << std::endl; else RsErr() << "Null Data" << std::endl; RsErr() << " size: " << static_cast(size) << " *size: " << (size ? *size : 0) << std::endl << " this should never happen!" << std::endl; print_stacktrace(); return nullptr; } if(!!(mFlags & RsSerializationFlags::SKIP_HEADER)) { RsErr() << __PRETTY_FUNCTION__ << " Cannot deserialise item with flag " << "SKIP_HEADER. Check your code!" << std::endl; print_stacktrace(); return nullptr; } uint32_t rstype = getRsItemId(const_cast((const void*)data)) ; RsItem *item = create_item(getRsItemService(rstype),getRsItemSubType(rstype)) ; if(!item) { RS_ERR(typeid(*this).name()) << ": cannot deserialise unknown item subtype " << std::hex << (int)getRsItemSubType(rstype) << std::dec << std::endl << "Data is: " << hexDump(data,std::min(50u,*size)) << ((*size>50)?"...":"") << std::endl; return nullptr; } SerializeContext ctx( const_cast(static_cast(data)), *size, mFlags ); ctx.mOffset = 8 ; item->serial_process(RsGenericSerializer::DESERIALIZE, ctx) ; if(ctx.mSize < ctx.mOffset) { RS_ERR("offset does not match expected size!"); delete item ; return NULL ; } *size = ctx.mOffset ; if(ctx.mOk) return item ; delete item ; return NULL ; } RsItem *RsConfigSerializer::deserialise(void *data, uint32_t *size) { if(!!(mFlags & RsSerializationFlags::SKIP_HEADER)) { RsErr() << __PRETTY_FUNCTION__ << " Cannot deserialise item with flag " << "SKIP_HEADER. Check your code!" << std::endl; print_stacktrace(); return nullptr; } uint32_t rstype = getRsItemId(const_cast((const void*)data)) ; RsItem *item = create_item(getRsItemType(rstype),getRsItemSubType(rstype)) ; if(!item) { RS_ERR( typeid(*this).name(), ": cannot deserialise unknown item subtype ", std::hex, (int) getRsItemSubType(rstype), std::dec ) #ifndef RS_DISABLE_DEPRECATED_DEBUG_UTILS << " Data is: " << RsUtil::BinToHex(static_cast(data), std::min(50u,*size)) << ((*size>50)?"...":"") << std::endl #endif // RS_DISABLE_DEPRECATED_DEBUG_UTILS ; return nullptr; } SerializeContext ctx( const_cast(static_cast(data)), *size, mFlags ); ctx.mOffset = 8 ; item->serial_process(DESERIALIZE, ctx) ; if(ctx.mSize < ctx.mOffset) { std::cerr << "RsSerializer::deserialise(): ERROR. offset does not match expected size!" << std::endl; delete item ; return NULL ; } *size = ctx.mOffset ; if(ctx.mOk) return item ; delete item ; return NULL ; } bool RsGenericSerializer::serialise(RsItem* item, void* data, uint32_t* size) { uint32_t tlvsize = this->size(item); constexpr auto fName = __PRETTY_FUNCTION__; const auto failure = [=](std::error_condition ec) { RsErr() << fName << " " << ec << std::endl; print_stacktrace(); return false; }; if(tlvsize > *size) return failure(std::errc::no_buffer_space); SerializeContext ctx(static_cast(data), tlvsize, mFlags); if(!(mFlags & RsSerializationFlags::SKIP_HEADER)) { if(!setRsItemHeader(data, tlvsize, item->PacketId(), tlvsize)) return failure(std::errc::no_buffer_space); ctx.mOffset = 8; } item->serial_process(RsGenericSerializer::SERIALIZE,ctx); if(ctx.mSize != ctx.mOffset) return failure(std::errc::message_size); *size = ctx.mOffset; return true; } uint32_t RsGenericSerializer::size(RsItem *item) { SerializeContext ctx(nullptr, 0, mFlags); if(!!(mFlags & RsSerializationFlags::SKIP_HEADER)) ctx.mOffset = 0; else ctx.mOffset = 8; // header size item->serial_process(SIZE_ESTIMATE, ctx) ; return ctx.mOffset ; } void RsGenericSerializer::print(RsItem *item) { SerializeContext ctx(nullptr, 0, mFlags); std::cerr << "***** RsItem class: \"" << typeid(*item).name() << "\" *****" << std::endl; item->serial_process(PRINT, ctx) ; std::cerr << "******************************" << std::endl; } uint32_t RsRawSerialiser::size(RsItem *i) { RsRawItem *item = dynamic_cast(i); if (item) { return item->getRawLength(); } return 0; } /* serialise the data to the buffer */ bool RsRawSerialiser::serialise(RsItem *i, void *data, uint32_t *pktsize) { RsRawItem *item = dynamic_cast(i); if (!item) { return false; } #ifdef RSSERIAL_DEBUG std::cerr << "RsRawSerialiser::serialise() serializing raw item. pktsize : " << *pktsize; #endif uint32_t tlvsize = item->getRawLength(); #ifdef RSSERIAL_DEBUG std::cerr << "tlvsize : " << tlvsize << std::endl; #endif if (*pktsize < tlvsize) return false; /* not enough space */ if (tlvsize > getRsPktMaxSize()) { std::cerr << "(EE) Serialised packet is too big. Maximum allowed size is " << getRsPktMaxSize() << ". Serialised size is " << tlvsize << ". Please tune your service to correctly split packets" << std::endl; return false; /* packet too big */ } *pktsize = tlvsize; /* its serialised already!!! */ memcpy(data, item->getRawData(), tlvsize); return true; } RsItem *RsRawSerialiser::deserialise(void *data, uint32_t *pktsize) { /* get the type and size */ uint32_t rstype = getRsItemId(data); uint32_t rssize = getRsItemSize(data); if (RS_PKT_VERSION_SERVICE != getRsItemVersion(rstype)) { return NULL; /* wrong type */ } if (*pktsize < rssize) /* check size */ return NULL; /* not enough data */ if (rssize > getRsPktMaxSize()) return NULL; /* packet too big */ /* set the packet length */ *pktsize = rssize; RsRawItem *item = new RsRawItem(rstype, rssize); void *item_data = item->getRawData(); memcpy(item_data, data, rssize); return item; } RsGenericSerializer::SerializeContext::SerializeContext( uint8_t* data, uint32_t size, RsSerializationFlags flags, RsJson::AllocatorType* allocator ) : mData(data), mSize(size), mOffset(0), mOk(true), mFlags(flags), mJson(rapidjson::kObjectType, allocator) { if(data) { if(size == 0) { RsFatal() << __PRETTY_FUNCTION__ << " data passed without " << "size! This make no sense report to developers!" << std::endl; print_stacktrace(); exit(-EINVAL); } if(!!(flags & RsSerializationFlags::YIELDING)) { RsFatal() << __PRETTY_FUNCTION__ << " Attempt to create a " << "binary serialization context with " << "SERIALIZATION_FLAG_YIELDING! " << "This make no sense report to developers!" << std::endl; print_stacktrace(); exit(-EINVAL); } } }