Merge pull request #1829 from G10h4ck/rsfiles_links

RsFiles links support in libretroshare + a bunch of fixes
This commit is contained in:
G10h4ck 2020-04-20 17:12:04 +02:00 committed by GitHub
commit 2b44492cb6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
77 changed files with 2949 additions and 1667 deletions

View File

@ -12,13 +12,17 @@ build-and-test:
script: script:
- > - >
if [ -n "$CI_MERGE_REQUEST_ID" ]; then if [ -n "$CI_MERGE_REQUEST_ID" ]; then
MR_ARGS="--build-arg REPO_URL=$CI_MERGE_REQUEST_SOURCE_PROJECT_URL" ; REPO_ARGS="--build-arg REPO_URL=$CI_MERGE_REQUEST_SOURCE_PROJECT_URL" ;
MR_ARGS="$MR_ARGS --build-arg REPO_BRANCH=$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME" ; REPO_ARGS="$REPO_ARGS --build-arg REPO_BRANCH=$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME" ;
export MR_ARGS ; else
fi REPO_ARGS="--build-arg REPO_URL=$CI_REPOSITORY_URL" ;
REPO_ARGS="$REPO_ARGS --build-arg REPO_BRANCH=$CI_COMMIT_BRANCH" ;
fi ;
export REPO_ARGS ;
echo REPO_ARGS=$REPO_ARGS ;
- mkdir Dockercontext - mkdir Dockercontext
- > - >
docker build -t retroshare:testing $MR_ARGS docker build -t retroshare:testing $REPO_ARGS
--file $CI_PROJECT_DIR/build_scripts/GitlabCI/gitlabCI.Dockerfile --file $CI_PROJECT_DIR/build_scripts/GitlabCI/gitlabCI.Dockerfile
Dockercontext Dockercontext
- > - >

View File

@ -19,7 +19,7 @@
# SPDX-FileCopyrightText: Retroshare Team <contact@retroshare.cc> # SPDX-FileCopyrightText: Retroshare Team <contact@retroshare.cc>
# SPDX-License-Identifier: LGPL-3.0-or-later # SPDX-License-Identifier: LGPL-3.0-or-later
CONFIG += c++11 CONFIG += c++14
!include("retroshare.pri"): error("Could not include file retroshare.pri") !include("retroshare.pri"): error("Could not include file retroshare.pri")

View File

@ -7,7 +7,8 @@ ARG REPO_BRANCH=master
RUN \ RUN \
cd RetroShare && git remote add testing $REPO_URL && \ cd RetroShare && git remote add testing $REPO_URL && \
git fetch --tags testing $REPO_BRANCH && \ git fetch --tags testing $REPO_BRANCH && \
git reset --hard testing/$REPO_BRANCH git reset --hard testing/$REPO_BRANCH && \
git --no-pager log --max-count 1
RUN \ RUN \
mkdir RetroShare-build && cd RetroShare-build && \ mkdir RetroShare-build && cd RetroShare-build && \
qmake ../RetroShare CONFIG+=no_retroshare_gui \ qmake ../RetroShare CONFIG+=no_retroshare_gui \

View File

@ -44,7 +44,7 @@ $%inputParamsDeserialization%$
const std::weak_ptr<rb::Service> weakService(mService); const std::weak_ptr<rb::Service> weakService(mService);
const std::weak_ptr<rb::Session> weakSession(session); const std::weak_ptr<rb::Session> weakSession(session);
$%callbackName%$ = [this, weakService, weakSession]($%callbackParams%$) $%callbackName%$ = [weakService, weakSession]($%callbackParams%$)
{ {
auto session = weakSession.lock(); auto session = weakSession.lock();
if(!session || session->is_closed()) return; if(!session || session->is_closed()) return;

View File

@ -221,7 +221,8 @@ bool DistributedChatService::checkSignature(RsChatLobbyBouncingObject *obj,const
mGixs->requestKey(obj->signature.keyId,peer_list,RsIdentityUsage(RS_SERVICE_TYPE_CHAT,RsIdentityUsage::CHAT_LOBBY_MSG_VALIDATION,RsGxsGroupId(),RsGxsMessageId(),obj->lobby_id)); mGixs->requestKey(obj->signature.keyId,peer_list,RsIdentityUsage(RS_SERVICE_TYPE_CHAT,RsIdentityUsage::CHAT_LOBBY_MSG_VALIDATION,RsGxsGroupId(),RsGxsMessageId(),obj->lobby_id));
uint32_t size = RsChatSerialiser(RsServiceSerializer::SERIALIZATION_FLAG_SIGNATURE).size(dynamic_cast<RsItem*>(obj)) ; uint32_t size = RsChatSerialiser(RsSerializationFlags::SIGNATURE)
.size(dynamic_cast<RsItem*>(obj));
RsTemporaryMemory memory(size) ; RsTemporaryMemory memory(size) ;
#ifdef DEBUG_CHAT_LOBBIES #ifdef DEBUG_CHAT_LOBBIES
@ -229,7 +230,8 @@ bool DistributedChatService::checkSignature(RsChatLobbyBouncingObject *obj,const
std::cerr << " signature id: " << obj->signature.keyId << std::endl; std::cerr << " signature id: " << obj->signature.keyId << std::endl;
#endif #endif
if(!RsChatSerialiser(RsServiceSerializer::SERIALIZATION_FLAG_SIGNATURE).serialise(dynamic_cast<RsItem*>(obj),memory,&size)) if( !RsChatSerialiser(RsSerializationFlags::SIGNATURE)
.serialise(dynamic_cast<RsItem*>(obj),memory,&size) )
{ {
std::cerr << " (EE) Cannot serialise message item. " << std::endl; std::cerr << " (EE) Cannot serialise message item. " << std::endl;
return false ; return false ;
@ -1003,10 +1005,12 @@ bool DistributedChatService::locked_initLobbyBouncableObject(const ChatLobbyId&
// now sign the object, if the lobby expects it // now sign the object, if the lobby expects it
uint32_t size = RsChatSerialiser(RsServiceSerializer::SERIALIZATION_FLAG_SIGNATURE).size(dynamic_cast<RsItem*>(&item)) ; uint32_t size = RsChatSerialiser(RsSerializationFlags::SIGNATURE)
.size(dynamic_cast<RsItem*>(&item));
RsTemporaryMemory memory(size) ; RsTemporaryMemory memory(size) ;
if(!RsChatSerialiser(RsServiceSerializer::SERIALIZATION_FLAG_SIGNATURE).serialise(dynamic_cast<RsItem*>(&item),memory,&size)) if( !RsChatSerialiser(RsSerializationFlags::SIGNATURE)
.serialise(dynamic_cast<RsItem*>(&item),memory,&size) )
{ {
std::cerr << "(EE) Cannot sign message item. " << std::endl; std::cerr << "(EE) Cannot sign message item. " << std::endl;
return false ; return false ;

View File

@ -70,23 +70,14 @@ void RsChatMsgItem::serial_process(RsGenericSerializer::SerializeJob j,RsGeneric
/*************************************************************************/ /*************************************************************************/
RsChatAvatarItem::~RsChatAvatarItem()
{
if(image_data != NULL)
{
free(image_data) ;
image_data = NULL ;
}
}
void RsChatLobbyBouncingObject::serial_process(RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext& ctx) void RsChatLobbyBouncingObject::serial_process(RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext& ctx)
{ {
RsTypeSerializer::serial_process(j,ctx,lobby_id,"lobby_id") ; RsTypeSerializer::serial_process(j,ctx,lobby_id,"lobby_id") ;
RsTypeSerializer::serial_process(j,ctx,msg_id ,"msg_id") ; RsTypeSerializer::serial_process(j,ctx,msg_id ,"msg_id") ;
RsTypeSerializer::serial_process(j,ctx,TLV_TYPE_STR_NAME,nick,"nick") ; RsTypeSerializer::serial_process(j,ctx,TLV_TYPE_STR_NAME,nick,"nick") ;
if(!(ctx.mFlags & RsServiceSerializer::SERIALIZATION_FLAG_SIGNATURE)) if(!(ctx.mFlags & RsSerializationFlags::SIGNATURE))
RsTypeSerializer::serial_process<RsTlvItem>(j,ctx,signature,"signature") ; RS_SERIAL_PROCESS(signature);
} }
void RsChatLobbyMsgItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) void RsChatLobbyMsgItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx)

View File

@ -346,14 +346,20 @@ class RsChatStatusItem: public RsChatItem
// //
class RsChatAvatarItem: public RsChatItem class RsChatAvatarItem: public RsChatItem
{ {
public: public:
RsChatAvatarItem() :RsChatItem(RS_PKT_SUBTYPE_CHAT_AVATAR) {setPriorityLevel(QOS_PRIORITY_RS_CHAT_AVATAR_ITEM) ;} RsChatAvatarItem():
RsChatItem(RS_PKT_SUBTYPE_CHAT_AVATAR),
image_size(0), image_data(nullptr)
{ setPriorityLevel(QOS_PRIORITY_RS_CHAT_AVATAR_ITEM); }
virtual ~RsChatAvatarItem() ; ~RsChatAvatarItem() override { free(image_data); }
void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx);
uint32_t image_size ; // size of data in bytes void serial_process(
unsigned char *image_data ; // image RsGenericSerializer::SerializeJob j,
RsGenericSerializer::SerializeContext& ctx) override;
uint32_t image_size; /// size of data in bytes
unsigned char* image_data ; /// image data
}; };
@ -369,9 +375,8 @@ struct PrivateOugoingMapItem : RsChatItem
struct RsChatSerialiser : RsServiceSerializer struct RsChatSerialiser : RsServiceSerializer
{ {
RsChatSerialiser(SerializationFlags flags = SERIALIZATION_FLAG_NONE) : RsChatSerialiser(RsSerializationFlags flags = RsSerializationFlags::NONE):
RsServiceSerializer( RS_SERVICE_TYPE_CHAT, RsServiceSerializer(RS_SERVICE_TYPE_CHAT, flags) {}
RsGenericSerializer::FORMAT_BINARY, flags ) {}
virtual RsItem *create_item(uint16_t service_id,uint8_t item_sub_id) const; virtual RsItem *create_item(uint16_t service_id,uint8_t item_sub_id) const;
}; };

View File

@ -3,7 +3,9 @@
* * * *
* libretroshare: retroshare core library * * libretroshare: retroshare core library *
* * * *
* Copyright 2018 by Retroshare Team <retroshare.project@gmail.com> * * Copyright (C) 2018 Retroshare Team <contact@retroshare.cc> *
* Copyright (C) 2020 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2020 Asociación Civil Altermundi <info@altermundi.net> *
* * * *
* This program is free software: you can redistribute it and/or modify * * This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as * * it under the terms of the GNU Lesser General Public License as *
@ -20,40 +22,100 @@
* * * *
******************************************************************************/ ******************************************************************************/
#include <iomanip> #include <iomanip>
#include <util/radix64.h>
#include <util/rsdir.h>
#include "util/radix64.h"
#include "util/rsbase64.h"
#include "util/rsdir.h"
#include "retroshare/rsfiles.h"
#include "file_sharing_defaults.h" #include "file_sharing_defaults.h"
#include "filelist_io.h" #include "filelist_io.h"
#include "file_tree.h" #include "serialiser/rstypeserializer.h"
std::string FileTreeImpl::toRadix64() const void RsFileTree::DirData::serial_process(
RsGenericSerializer::SerializeJob j,
RsGenericSerializer::SerializeContext& ctx )
{ {
unsigned char *buff = NULL ; RS_SERIAL_PROCESS(name);
uint32_t size = 0 ; RS_SERIAL_PROCESS(subdirs);
RS_SERIAL_PROCESS(subfiles);
serialise(buff,size) ;
std::string res ;
Radix64::encode(buff,size,res) ;
free(buff) ;
return res ;
} }
FileTree *FileTree::create(const std::string& radix64_string) void RsFileTree::FileData::serial_process(
RsGenericSerializer::SerializeJob j,
RsGenericSerializer::SerializeContext& ctx )
{ {
FileTreeImpl *ft = new FileTreeImpl ; RS_SERIAL_PROCESS(name);
RS_SERIAL_PROCESS(size);
RS_SERIAL_PROCESS(hash);
}
/*static*/ std::tuple<std::unique_ptr<RsFileTree>, std::error_condition>
RsFileTree::fromBase64(const std::string& base64)
{
const auto failure = [](std::error_condition ec)
{ return std::make_tuple(nullptr, ec); };
if(base64.empty()) return failure(std::errc::invalid_argument);
std::error_condition ec;
std::vector<uint8_t> mem;
if( (ec = RsBase64::decode(base64, mem)) ) return failure(ec);
RsGenericSerializer::SerializeContext ctx(
mem.data(), static_cast<uint32_t>(mem.size()),
RsSerializationFlags::INTEGER_VLQ );
std::unique_ptr<RsFileTree> ft(new RsFileTree);
ft->serial_process(
RsGenericSerializer::SerializeJob::DESERIALIZE, ctx);
if(ctx.mOk) return std::make_tuple(std::move(ft), std::error_condition());
return failure(std::errc::invalid_argument);
}
std::string RsFileTree::toBase64() const
{
RsGenericSerializer::SerializeContext ctx;
ctx.mFlags = RsSerializationFlags::INTEGER_VLQ;
RsFileTree* ncThis = const_cast<RsFileTree*>(this);
ncThis->serial_process(
RsGenericSerializer::SerializeJob::SIZE_ESTIMATE, ctx );
std::vector<uint8_t> buf(ctx.mOffset);
ctx.mSize = ctx.mOffset; ctx.mOffset = 0; ctx.mData = buf.data();
ncThis->serial_process(
RsGenericSerializer::SerializeJob::SERIALIZE, ctx );
std::string result;
RsBase64::encode(ctx.mData, ctx.mSize, result, false, true);
return result;
}
std::string RsFileTree::toRadix64() const
{
unsigned char* buff = nullptr;
uint32_t size = 0;
serialise(buff, size);
std::string res;
Radix64::encode(buff,size,res);
free(buff);
return res;
}
std::unique_ptr<RsFileTree> RsFileTree::fromRadix64(
const std::string& radix64_string )
{
std::unique_ptr<RsFileTree> ft(new RsFileTree);
std::vector<uint8_t> mem = Radix64::decode(radix64_string); std::vector<uint8_t> mem = Radix64::decode(radix64_string);
ft->deserialise(mem.data(),mem.size()) ; if(ft->deserialise(mem.data(), static_cast<uint32_t>(mem.size())))
return ft;
return ft ; return nullptr;
} }
void FileTreeImpl::recurs_buildFileTree(FileTreeImpl& ft,uint32_t index,const DirDetails& dd,bool remote,bool remove_top_dirs) void RsFileTree::recurs_buildFileTree(
RsFileTree& ft, uint32_t index, const DirDetails& dd, bool remote,
bool remove_top_dirs )
{ {
RsDbg() << __PRETTY_FUNCTION__ << " index: " << index << std::endl;
if(ft.mDirs.size() <= index) if(ft.mDirs.size() <= index)
ft.mDirs.resize(index+1) ; ft.mDirs.resize(index+1) ;
@ -67,14 +129,14 @@ void FileTreeImpl::recurs_buildFileTree(FileTreeImpl& ft,uint32_t index,const Di
DirDetails dd2 ; DirDetails dd2 ;
FileSearchFlags flags = remote?RS_FILE_HINTS_REMOTE:RS_FILE_HINTS_LOCAL ; FileSearchFlags flags = remote ? RS_FILE_HINTS_REMOTE : RS_FILE_HINTS_LOCAL;
for(uint32_t i=0;i<dd.children.size();++i) for(uint32_t i=0;i<dd.children.size();++i)
if(rsFiles->RequestDirDetails(dd.children[i].ref,dd2,flags)) if(rsFiles->RequestDirDetails(dd.children[i].ref,dd2,flags))
{ {
if(dd.children[i].type == DIR_TYPE_FILE) if(dd.children[i].type == DIR_TYPE_FILE)
{ {
FileTree::FileData f ; FileData f ;
f.name = dd2.name ; f.name = dd2.name ;
f.size = dd2.count ; f.size = dd2.count ;
f.hash = dd2.hash ; f.hash = dd2.hash ;
@ -97,33 +159,50 @@ void FileTreeImpl::recurs_buildFileTree(FileTreeImpl& ft,uint32_t index,const Di
std::cerr << "(EE) Cannot request dir details for pointer " << dd.children[i].ref << std::endl; std::cerr << "(EE) Cannot request dir details for pointer " << dd.children[i].ref << std::endl;
} }
bool FileTreeImpl::getDirectoryContent(uint32_t index,std::string& name,std::vector<uint32_t>& subdirs,std::vector<FileData>& subfiles) const bool RsFileTree::getDirectoryContent(
std::string& name, std::vector<uint64_t>& subdirs,
std::vector<FileData>& subfiles, uint64_t index_p ) const
{ {
if(index >= mDirs.size()) // Avoid warnings on Android armv7
return false ; using sz_t = std::vector<FileData>::size_type;
sz_t index = static_cast<sz_t>(index_p);
if(index >= mDirs.size()) return false;
name = mDirs[index].name; name = mDirs[index].name;
subdirs = mDirs[index].subdirs ; subdirs = mDirs[index].subdirs ;
subfiles.clear() ; subfiles.clear() ;
for(uint32_t i=0;i<mDirs[index].subfiles.size();++i) for(sz_t i=0; i < mDirs[index].subfiles.size(); ++i)
subfiles.push_back(mFiles[mDirs[index].subfiles[i]]); subfiles.push_back(mFiles[static_cast<sz_t>(mDirs[index].subfiles[i])]);
return true ; return true;
} }
FileTree *FileTree::create(const DirDetails& dd, bool remote,bool remove_top_dirs) std::unique_ptr<RsFileTree> RsFileTree::fromDirDetails(
const DirDetails& dd, bool remote ,bool remove_top_dirs )
{ {
FileTreeImpl *ft = new FileTreeImpl ; std::unique_ptr<RsFileTree>ft(new RsFileTree);
if(dd.type == DIR_TYPE_FILE)
{
FileData fd;
fd.name = dd.name; fd.hash = dd.hash; fd.size = dd.count;
ft->mFiles.push_back(fd);
ft->mTotalFiles = 1;
ft->mTotalSize = fd.size;
FileTreeImpl::recurs_buildFileTree(*ft,0,dd,remote,remove_top_dirs) ; DirData dd;
dd.name = "/";
return ft ; dd.subfiles.push_back(0);
ft->mDirs.push_back(dd);
}
else recurs_buildFileTree(*ft, 0, dd, remote, remove_top_dirs );
return ft;
} }
typedef FileListIO::read_error read_error ; typedef FileListIO::read_error read_error ;
bool FileTreeImpl::deserialise(unsigned char *buffer,uint32_t buffer_size) bool RsFileTree::deserialise(unsigned char *buffer,uint32_t buffer_size)
{ {
uint32_t buffer_offset = 0 ; uint32_t buffer_offset = 0 ;
@ -218,7 +297,7 @@ bool FileTreeImpl::deserialise(unsigned char *buffer,uint32_t buffer_size)
return true ; return true ;
} }
bool FileTreeImpl::serialise(unsigned char *& buffer,uint32_t& buffer_size) const bool RsFileTree::serialise(unsigned char *& buffer,uint32_t& buffer_size) const
{ {
buffer = 0 ; buffer = 0 ;
uint32_t buffer_offset = 0 ; uint32_t buffer_offset = 0 ;
@ -234,7 +313,11 @@ bool FileTreeImpl::serialise(unsigned char *& buffer,uint32_t& buffer_size) cons
{ {
// Write some header // Write some header
if(!FileListIO::writeField(buffer,buffer_size,buffer_offset,FILE_LIST_IO_TAG_LOCAL_DIRECTORY_VERSION,(uint32_t) FILE_LIST_IO_LOCAL_DIRECTORY_TREE_VERSION_0001)) throw std::runtime_error("Write error") ; if(!FileListIO::writeField(
buffer, buffer_size, buffer_offset,
FILE_LIST_IO_TAG_LOCAL_DIRECTORY_VERSION,
(uint32_t) FILE_LIST_IO_LOCAL_DIRECTORY_TREE_VERSION_0001 ) )
throw std::runtime_error("Write error") ;
if(!FileListIO::writeField(buffer,buffer_size,buffer_offset,FILE_LIST_IO_TAG_RAW_NUMBER,(uint32_t) mFiles.size())) throw std::runtime_error("Write error") ; if(!FileListIO::writeField(buffer,buffer_size,buffer_offset,FILE_LIST_IO_TAG_RAW_NUMBER,(uint32_t) mFiles.size())) throw std::runtime_error("Write error") ;
if(!FileListIO::writeField(buffer,buffer_size,buffer_offset,FILE_LIST_IO_TAG_RAW_NUMBER,(uint32_t) mDirs.size())) throw std::runtime_error("Write error") ; if(!FileListIO::writeField(buffer,buffer_size,buffer_offset,FILE_LIST_IO_TAG_RAW_NUMBER,(uint32_t) mDirs.size())) throw std::runtime_error("Write error") ;
@ -292,28 +375,4 @@ bool FileTreeImpl::serialise(unsigned char *& buffer,uint32_t& buffer_size) cons
} }
} }
void FileTreeImpl::print() const RsFileTree::~RsFileTree() = default;
{
std::cerr << "File hierarchy: name=" << mDirs[0].name << " size=" << mTotalSize << std::endl;
recurs_print(0," ") ;
}
void FileTreeImpl::recurs_print(uint32_t index,const std::string& indent) const
{
if(index >= mDirs.size())
{
std::cerr << "(EE) inconsistent FileTree structure" << std::endl;
return;
}
std::cerr << indent << mDirs[index].name << std::endl;
for(uint32_t i=0;i<mDirs[index].subdirs.size();++i)
recurs_print(mDirs[index].subdirs[i],indent+" ") ;
for(uint32_t i=0;i<mDirs[index].subfiles.size();++i)
{
const FileData& fd(mFiles[mDirs[index].subfiles[i]]) ;
std::cerr << indent << " " << fd.hash << " " << std::setprecision(8) << fd.size << " " << fd.name << std::endl;
}
}

View File

@ -38,7 +38,7 @@
#include "util/rsdiscspace.h" #include "util/rsdiscspace.h"
#include "util/rsmemory.h" #include "util/rsmemory.h"
#include "util/rstime.h" #include "util/rstime.h"
#include "util/cxx17retrocompat.h"
#include "ft/ftcontroller.h" #include "ft/ftcontroller.h"
#include "ft/ftfilecreator.h" #include "ft/ftfilecreator.h"
@ -923,10 +923,15 @@ bool ftController::alreadyHaveFile(const RsFileHash& hash, FileInfo &info)
return false ; return false ;
} }
bool ftController::FileRequest(const std::string& fname, const RsFileHash& hash, bool ftController::FileRequest(
uint64_t size, const std::string& dest, TransferRequestFlags flags, const std::string& fname, const RsFileHash& hash, uint64_t size,
const std::list<RsPeerId> &_srcIds, uint16_t state) const std::string& dest, TransferRequestFlags flags,
const std::list<RsPeerId> &_srcIds, uint16_t state )
{ {
/* TODO: To support collections faithfully we need to be able to save
* the same file to multiple locations, both if already downloaded or
* incomplete */
std::list<RsPeerId> srcIds(_srcIds) ; std::list<RsPeerId> srcIds(_srcIds) ;
/* check if we have the file */ /* check if we have the file */
@ -965,8 +970,9 @@ bool ftController::FileRequest(const std::string& fname, const RsFileHash& hash
// create void file with the target name. // create void file with the target name.
FILE *f = RsDirUtil::rs_fopen(destination.c_str(),"w") ; FILE *f = RsDirUtil::rs_fopen(destination.c_str(),"w") ;
if(f == NULL) if(!f)
std::cerr << "Could not open file " << destination << " for writting." << std::endl ; RsErr() << __PRETTY_FUNCTION__ << " Could not write file "
<< destination << std::endl;
else else
fclose(f) ; fclose(f) ;
@ -979,12 +985,13 @@ bool ftController::FileRequest(const std::string& fname, const RsFileHash& hash
// //
if(size >= 1024ull*1024ull*((1ull << 32) - 1)) if(size >= 1024ull*1024ull*((1ull << 32) - 1))
{ {
std::cerr << "FileRequest Error: unexpected size. This is probably a bug." << std::endl; RsErr() << __PRETTY_FUNCTION__
std::cerr << " name = " << fname << std::endl ; << " unexpected size. This is probably a bug."
std::cerr << " flags = " << flags << std::endl ; << " name = " << fname
std::cerr << " dest = " << dest << std::endl ; << " flags = " << flags
std::cerr << " size = " << size << std::endl ; << " dest = " << dest
return false ; << " size = " << size << std::endl;
return false;
} }
/* If file transfer is not enabled .... /* If file transfer is not enabled ....
@ -1004,8 +1011,8 @@ bool ftController::FileRequest(const std::string& fname, const RsFileHash& hash
} }
} }
// remove the sources from the list, if they don't have clearance for direct transfer. This happens only for non cache files. /* remove the sources from the list, if they don't have clearance for direct
// * transfer. This happens only for non cache files. */
for(std::list<RsPeerId>::iterator it = srcIds.begin(); it != srcIds.end(); ) for(std::list<RsPeerId>::iterator it = srcIds.begin(); it != srcIds.end(); )
{ {
bool bAllowDirectDL = false; bool bAllowDirectDL = false;
@ -1052,11 +1059,10 @@ bool ftController::FileRequest(const std::string& fname, const RsFileHash& hash
* This is important as some guis request duplicate files regularly. * This is important as some guis request duplicate files regularly.
*/ */
{ {
RsStackMutex stack(ctrlMutex); /******* LOCKED ********/ RS_STACK_MUTEX(ctrlMutex);
std::map<RsFileHash, ftFileControl*>::const_iterator dit = mDownloads.find(hash);
auto dit = std::as_const(mDownloads).find(hash);
if (dit != mDownloads.end()) if (dit != mDownloads.end())
{ {
/* we already have it! */ /* we already have it! */
@ -1110,7 +1116,7 @@ bool ftController::FileRequest(const std::string& fname, const RsFileHash& hash
return true; return true;
} }
} /******* UNLOCKED ********/ } // RS_STACK_MUTEX(ctrlMutex); unlocked
if(mSearch && !(flags & RS_FILE_REQ_NO_SEARCH)) if(mSearch && !(flags & RS_FILE_REQ_NO_SEARCH))

View File

@ -20,6 +20,9 @@
* * * *
*******************************************************************************/ *******************************************************************************/
#include <algorithm>
#include <iostream>
#include "crypto/chacha20.h" #include "crypto/chacha20.h"
//const int ftserverzone = 29539; //const int ftserverzone = 29539;
@ -40,18 +43,16 @@
#include "retroshare/rstypes.h" #include "retroshare/rstypes.h"
#include "retroshare/rspeers.h" #include "retroshare/rspeers.h"
#include "retroshare/rsinit.h" #include "retroshare/rsinit.h"
#include "util/cxx17retrocompat.h"
#include "rsitems/rsfiletransferitems.h" #include "rsitems/rsfiletransferitems.h"
#include "rsitems/rsserviceids.h" #include "rsitems/rsserviceids.h"
#include "util/rsmemory.h"
#include "rsserver/p3face.h" #include "rsserver/p3face.h"
#include "turtle/p3turtle.h" #include "turtle/p3turtle.h"
#include "util/rsurl.h"
#include "util/rsdebug.h" #include "util/rsdebug.h"
#include "util/rsdir.h" #include "util/rsdir.h"
#include "util/rsprint.h" #include "util/rsprint.h"
#include <iostream>
#include "util/rstime.h" #include "util/rstime.h"
#ifdef RS_DEEP_FILES_INDEX #ifdef RS_DEEP_FILES_INDEX
@ -66,6 +67,18 @@
#define FTSERVER_DEBUG() std::cerr << time(NULL) << " : FILE_SERVER : " << __FUNCTION__ << " : " #define FTSERVER_DEBUG() std::cerr << time(NULL) << " : FILE_SERVER : " << __FUNCTION__ << " : "
#define FTSERVER_ERROR() std::cerr << "(EE) FILE_SERVER ERROR : " #define FTSERVER_ERROR() std::cerr << "(EE) FILE_SERVER ERROR : "
/*static*/ const RsFilesErrorCategory RsFilesErrorCategory::instance;
/*static*/ const std::string RsFiles::DEFAULT_FILES_BASE_URL =
"retroshare:///files";
/*static*/ const std::string RsFiles::FILES_URL_COUNT_FIELD = "filesCount";
/*static*/ const std::string RsFiles::FILES_URL_DATA_FIELD = "filesData";
// Use a 5 character word so there is no mistake it isn't base64 as 5%4=1
/*static*/ const std::string RsFiles::FILES_URL_FAGMENT_FORWARD = "fragm";
/*static*/ const std::string RsFiles::FILES_URL_NAME_FIELD = "filesName";
/*static*/ const std::string RsFiles::FILES_URL_SIZE_FIELD = "filesSize";
static const rstime_t FILE_TRANSFER_LOW_PRIORITY_TASKS_PERIOD = 5 ; // low priority tasks handling every 5 seconds static const rstime_t FILE_TRANSFER_LOW_PRIORITY_TASKS_PERIOD = 5 ; // low priority tasks handling every 5 seconds
static const rstime_t FILE_TRANSFER_MAX_DELAY_BEFORE_DROP_USAGE_RECORD = 10 ; // keep usage records for 10 secs at most. static const rstime_t FILE_TRANSFER_MAX_DELAY_BEFORE_DROP_USAGE_RECORD = 10 ; // keep usage records for 10 secs at most.
@ -283,7 +296,10 @@ bool ftServer::alreadyHaveFile(const RsFileHash& hash, FileInfo &info)
return mFileDatabase->search(hash, RS_FILE_HINTS_LOCAL, info); return mFileDatabase->search(hash, RS_FILE_HINTS_LOCAL, info);
} }
bool ftServer::FileRequest(const std::string& fname, const RsFileHash& hash, uint64_t size, const std::string& dest, TransferRequestFlags flags, const std::list<RsPeerId>& srcIds) bool ftServer::FileRequest(
const std::string& fname, const RsFileHash& hash, uint64_t size,
const std::string& dest, TransferRequestFlags flags,
const std::list<RsPeerId>& srcIds )
{ {
#ifdef SERVER_DEBUG #ifdef SERVER_DEBUG
FTSERVER_DEBUG() << "Requesting " << fname << std::endl ; FTSERVER_DEBUG() << "Requesting " << fname << std::endl ;
@ -295,6 +311,93 @@ bool ftServer::FileRequest(const std::string& fname, const RsFileHash& hash, uin
return true ; return true ;
} }
std::error_condition ftServer::requestFiles(
const RsFileTree& collection, const std::string& destPath,
const std::vector<RsPeerId>& srcIds, FileRequestFlags flags )
{
constexpr auto fname = __PRETTY_FUNCTION__;
const auto dirsCount = collection.mDirs.size();
const auto filesCount = collection.mFiles.size();
Dbg2() << fname << " dirsCount: " << dirsCount
<< " filesCount: " << filesCount << std::endl;
if(!dirsCount)
{
RsErr() << fname << " Directories list empty in collection "
<< std::endl;
return std::errc::not_a_directory;
}
if(!filesCount)
{
RsErr() << fname << " Files list empty in collection " << std::endl;
return std::errc::invalid_argument;
}
if(filesCount != collection.mTotalFiles)
{
RsErr() << fname << " Files count mismatch" << std::endl;
return std::errc::invalid_argument;
}
std::string basePath = destPath.empty() ? getDownloadDirectory() : destPath;
// Track how many time a directory have been explored
std::vector<uint32_t> dirsSeenCnt(dirsCount, 0);
// <directory handle, parent path>
using StackEntry = std::tuple<uint64_t, std::string>;
std::deque<StackEntry> dStack = { std::make_tuple(0, basePath) };
const auto exploreDir = [&](const StackEntry& se)-> std::error_condition
{
uint64_t dirHandle; std::string parentPath;
std::tie(dirHandle, parentPath) = se;
const auto& dirData = collection.mDirs[dirHandle];
auto& seenTimes = dirsSeenCnt[dirHandle];
std::string dirPath = RsDirUtil::makePath(parentPath, dirData.name);
/* This check is not perfect but is cheap and interrupt loop exploration
* before it becomes pathological */
if(seenTimes++ > dirsCount)
{
RsErr() << fname << " loop detected! dir: "
<< dirHandle << " \"" << dirPath
<< "\" explored too many times" << std::endl;
return std::errc::too_many_symbolic_link_levels;
}
for(auto fHandle: dirData.subfiles)
{
if(fHandle >= filesCount) return std::errc::argument_out_of_domain;
const RsFileTree::FileData& fData = collection.mFiles[fHandle];
bool fr =
FileRequest( fData.name, fData.hash, fData.size,
dirPath,
TransferRequestFlags::fromEFT<FileRequestFlags>(flags),
std::list<RsPeerId>(srcIds.begin(), srcIds.end()) );
Dbg2() << fname << " requested: " << fr << " "
<< fData.hash << " -> " << dirPath << std::endl;
}
for(auto dHandle: dirData.subdirs)
dStack.push_back(std::make_tuple(dHandle, dirPath));
return std::error_condition();
};
while(!dStack.empty())
{
if(std::error_condition ec = exploreDir(dStack.front())) return ec;
dStack.pop_front();
}
return std::error_condition();
}
bool ftServer::activateTunnels(const RsFileHash& hash,uint32_t encryption_policy,TransferRequestFlags flags,bool onoff) bool ftServer::activateTunnels(const RsFileHash& hash,uint32_t encryption_policy,TransferRequestFlags flags,bool onoff)
{ {
RsFileHash hash_of_hash ; RsFileHash hash_of_hash ;
@ -740,7 +843,7 @@ bool ftServer::findChildPointer(void *ref, int row, void *& result, FileSearchFl
} }
bool ftServer::requestDirDetails( bool ftServer::requestDirDetails(
DirDetails &details, std::uintptr_t handle, FileSearchFlags flags ) DirDetails &details, uint64_t handle, FileSearchFlags flags )
{ return RequestDirDetails(reinterpret_cast<void*>(handle), details, flags); } { return RequestDirDetails(reinterpret_cast<void*>(handle), details, flags); }
int ftServer::RequestDirDetails(void *ref, DirDetails &details, FileSearchFlags flags) int ftServer::RequestDirDetails(void *ref, DirDetails &details, FileSearchFlags flags)
@ -1872,15 +1975,16 @@ void ftServer::ftReceiveSearchResult(RsTurtleFTSearchResultItem *item)
hasCallback = true; hasCallback = true;
std::vector<TurtleFileInfoV2> cRes; std::vector<TurtleFileInfoV2> cRes;
for( const auto& tfiold : item->result) for(auto& res: std::as_const(item->result))
cRes.push_back(tfiold); cRes.push_back(TurtleFileInfoV2(res));
cbpt->second.first(cRes); cbpt->second.first(cRes);
} }
} // end RS_STACK_MUTEX(mSearchCallbacksMapMutex); } // end RS_STACK_MUTEX(mSearchCallbacksMapMutex);
if(!hasCallback) if(!hasCallback)
RsServer::notify()->notifyTurtleSearchResult(item->PeerId(),item->request_id, item->result ); RsServer::notify()->notifyTurtleSearchResult(
item->PeerId(), item->request_id, item->result );
} }
bool ftServer::receiveSearchRequest( bool ftServer::receiveSearchRequest(
@ -2101,3 +2205,144 @@ RsFileItem::RsFileItem(RsFileItemType subtype) :
void RsFileSearchRequestItem::clear() { queryString.clear(); } void RsFileSearchRequestItem::clear() { queryString.clear(); }
void RsFileSearchResultItem::clear() { mResults.clear(); } void RsFileSearchResultItem::clear() { mResults.clear(); }
std::error_condition RsFilesErrorCategory::default_error_condition(int ev)
const noexcept
{
switch(static_cast<RsFilesErrorNum>(ev))
{
case RsFilesErrorNum::FILES_HANDLE_NOT_FOUND:
return std::errc::invalid_argument;
default:
return std::error_condition(ev, *this);
}
}
std::error_condition ftServer::dirDetailsToLink(
std::string& link,
const DirDetails& dirDetails, bool fragSneak, const std::string& baseUrl )
{
std::unique_ptr<RsFileTree> tFileTree =
RsFileTree::fromDirDetails(dirDetails, false);
if(!tFileTree) return std::errc::invalid_argument;
link = tFileTree->toBase64();
if(!baseUrl.empty())
{
RsUrl tUrl(baseUrl);
tUrl.setQueryKV(FILES_URL_COUNT_FIELD,
std::to_string(tFileTree->mTotalFiles) )
.setQueryKV(FILES_URL_NAME_FIELD, dirDetails.name)
.setQueryKV( FILES_URL_SIZE_FIELD,
std::to_string(tFileTree->mTotalSize) );
if(fragSneak)
tUrl.setQueryKV(FILES_URL_DATA_FIELD, FILES_URL_FAGMENT_FORWARD)
.setFragment(link);
else tUrl.setQueryKV(FILES_URL_DATA_FIELD, link);
link = tUrl.toString();
}
return std::error_condition();
}
std::error_condition ftServer::exportCollectionLink(
std::string& link, uint64_t handle, bool fragSneak,
const std::string& baseUrl )
{
DirDetails tDirDet;
if(!requestDirDetails(tDirDet, handle))
return RsFilesErrorNum::FILES_HANDLE_NOT_FOUND;
return dirDetailsToLink(link, tDirDet, fragSneak, baseUrl);
}
/// @see RsFiles
std::error_condition ftServer::exportFileLink(
std::string& link, const RsFileHash& fileHash, uint64_t fileSize,
const std::string& fileName, bool fragSneak, const std::string& baseUrl )
{
if(fileHash.isNull() || !fileSize || fileName.empty())
return std::errc::invalid_argument;
DirDetails tDirDet;
tDirDet.type = DIR_TYPE_FILE;
tDirDet.name = fileName;
tDirDet.hash = fileHash;
tDirDet.count = fileSize;
return dirDetailsToLink(link, tDirDet, fragSneak, baseUrl);
}
std::error_condition ftServer::parseFilesLink(
const std::string& link, RsFileTree& collection )
{
RsUrl tUrl(link);
{
/* Handle retrocompatibility with old stile single file links
* retroshare://file?name=$FILE_NAME&size=$FILE_SIZE&hash=$FILE_HASH
*/
if( tUrl.scheme() == "retroshare" && tUrl.host() == "file"
&& tUrl.hasQueryK("name") && !tUrl.getQueryV("name")->empty()
&& tUrl.hasQueryK("size") && !tUrl.getQueryV("size")->empty()
&& tUrl.hasQueryK("hash") && !tUrl.getQueryV("hash")->empty() )
{
DirDetails dt;
dt.type = DIR_TYPE_FILE;
dt.hash = RsFileHash(*tUrl.getQueryV("hash"));
dt.name = *tUrl.getQueryV("name");
try
{
dt.count = std::stoull(*tUrl.getQueryV("size"));
std::unique_ptr<RsFileTree> ft;
if( !dt.hash.isNull() &&
(ft = RsFileTree::fromDirDetails(dt, true)) )
{
collection = *ft;
return std::error_condition();
}
}
catch (...) {}
}
}
{
/* Handle retrocompatibility with old stile collection links
* retroshare://collection?name=$NAME&size=$SIZE&radix=$RADIX&files=$COUNT
*/
if( tUrl.scheme() == "retroshare" && tUrl.host() == "collection"
&& tUrl.hasQueryK("name") && !tUrl.getQueryV("name")->empty()
&& tUrl.hasQueryK("size") && !tUrl.getQueryV("size")->empty()
&& tUrl.hasQueryK("radix") && !tUrl.getQueryV("radix")->empty()
&& tUrl.hasQueryK("files") && !tUrl.getQueryV("files")->empty() )
{
try
{
// Don't need the values just check they are valid numbers
std::stoull(*tUrl.getQueryV("size"));
std::stoull(*tUrl.getQueryV("files"));
auto ft = RsFileTree::fromRadix64(*tUrl.getQueryV("radix"));
if(ft)
{
collection = *ft;
return std::error_condition();
}
}
catch (...) {}
}
}
// Finaly handle the new files link format
rs_view_ptr<const std::string> radixPtr =
tUrl.getQueryV(FILES_URL_DATA_FIELD);
if(!radixPtr) radixPtr = &link;
else if(*radixPtr == FILES_URL_FAGMENT_FORWARD) radixPtr = &tUrl.fragment();
std::unique_ptr<RsFileTree> tft; std::error_condition ec;
std::tie(tft, ec) = RsFileTree::fromBase64(*radixPtr);
if(tft) collection = *tft;
return ec;
}

View File

@ -207,14 +207,39 @@ public:
virtual uint32_t filePermDirectDL() ; virtual uint32_t filePermDirectDL() ;
/// @see RsFiles /// @see RsFiles
virtual bool turtleSearchRequest( std::error_condition requestFiles(
const RsFileTree& collection,
const std::string& destPath = "",
const std::vector<RsPeerId>& srcIds = std::vector<RsPeerId>(),
FileRequestFlags flags = FileRequestFlags::ANONYMOUS_ROUTING
) override;
/// @see RsFiles
bool turtleSearchRequest(
const std::string& matchString, const std::string& matchString,
const std::function<void (const std::vector<TurtleFileInfoV2>& results)>& multiCallback, const std::function<void (const std::vector<TurtleFileInfoV2>& results)>& multiCallback,
rstime_t maxWait = 300 ); rstime_t maxWait = 300 ) override;
virtual TurtleSearchRequestId turtleSearch(const std::string& string_to_match) ; virtual TurtleSearchRequestId turtleSearch(const std::string& string_to_match) ;
virtual TurtleSearchRequestId turtleSearch(const RsRegularExpression::LinearizedExpression& expr) ; virtual TurtleSearchRequestId turtleSearch(const RsRegularExpression::LinearizedExpression& expr) ;
/// @see RsFiles
std::error_condition exportCollectionLink(
std::string& link, uint64_t handle, bool fragSneak = false,
const std::string& baseUrl = RsFiles::DEFAULT_FILES_BASE_URL
) override;
/// @see RsFiles
std::error_condition exportFileLink(
std::string& link, const RsFileHash& fileHash, uint64_t fileSize,
const std::string& fileName, bool fragSneak = false,
const std::string& baseUrl = RsFiles::DEFAULT_FILES_BASE_URL
) override;
/// @see RsFiles
std::error_condition parseFilesLink(
const std::string& link, RsFileTree& collection ) override;
/*** /***
* Control of Downloads Priority. * Control of Downloads Priority.
***/ ***/
@ -254,7 +279,7 @@ public:
/// @see RsFiles::RequestDirDetails /// @see RsFiles::RequestDirDetails
virtual bool requestDirDetails( virtual bool requestDirDetails(
DirDetails &details, std::uintptr_t handle = 0, DirDetails &details, uint64_t handle = 0,
FileSearchFlags flags = RS_FILE_HINTS_LOCAL ); FileSearchFlags flags = RS_FILE_HINTS_LOCAL );
virtual bool findChildPointer(void *ref, int row, void *& result, FileSearchFlags flags) ; virtual bool findChildPointer(void *ref, int row, void *& result, FileSearchFlags flags) ;
@ -365,11 +390,11 @@ protected:
bool findEncryptedHash(const RsPeerId& virtual_peer_id, RsFileHash& encrypted_hash); bool findEncryptedHash(const RsPeerId& virtual_peer_id, RsFileHash& encrypted_hash);
bool checkUploadLimit(const RsPeerId& pid,const RsFileHash& hash); bool checkUploadLimit(const RsPeerId& pid,const RsFileHash& hash);
private:
/**** INTERNAL FUNCTIONS ***/ std::error_condition dirDetailsToLink(
//virtual int reScanDirs(); std::string& link,
//virtual int check_dBUpdate(); const DirDetails& dirDetails, bool fragSneak,
const std::string& baseUrl );
private: private:

View File

@ -75,8 +75,8 @@ void RsDiscPgpKeyItem::clear()
{ {
pgpKeyId.clear(); pgpKeyId.clear();
free(bin_data); free(bin_data);
bin_data = nullptr; bin_data = nullptr;
bin_len=0; bin_len = 0;
} }
void RsDiscContactItem::clear() void RsDiscContactItem::clear()

View File

@ -84,17 +84,23 @@ class RsDiscPgpKeyItem: public RsDiscItem
{ {
public: public:
RsDiscPgpKeyItem() : RsDiscItem(RsGossipDiscoveryItemType::PGP_CERT_BINARY) RsDiscPgpKeyItem() :
RsDiscItem(RsGossipDiscoveryItemType::PGP_CERT_BINARY),
bin_data(nullptr), bin_len(0)
{ setPriorityLevel(QOS_PRIORITY_RS_DISC_PGP_CERT); } { setPriorityLevel(QOS_PRIORITY_RS_DISC_PGP_CERT); }
virtual ~RsDiscPgpKeyItem() { delete[](bin_data);bin_data=nullptr;bin_len=0;} ~RsDiscPgpKeyItem() override { free(bin_data); }
void clear() override; void clear() override;
void serial_process( RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext& ctx) override;
RsPgpId pgpKeyId; // duplicate information for practical reasons void serial_process(
unsigned char *bin_data; // binry key data allocated with new unsigned char[] RsGenericSerializer::SerializeJob j,
uint32_t bin_len; RsGenericSerializer::SerializeContext& ctx ) override;
/// duplicate information for practical reasons
RsPgpId pgpKeyId;
unsigned char* bin_data;
uint32_t bin_len;
}; };
class RS_DEPRECATED_FOR(RsDiscPgpKeyItem) RsDiscPgpCertItem: public RsDiscItem class RS_DEPRECATED_FOR(RsDiscPgpKeyItem) RsDiscPgpCertItem: public RsDiscItem

View File

@ -108,14 +108,6 @@ p3discovery2::p3discovery2(
// Add self into PGP FriendList. // Add self into PGP FriendList.
mFriendList[AuthGPG::getAuthGPG()->getGPGOwnId()] = DiscPgpInfo(); mFriendList[AuthGPG::getAuthGPG()->getGPGOwnId()] = DiscPgpInfo();
if(rsEvents)
rsEvents->registerEventsHandler(
RsEventType::GOSSIP_DISCOVERY,
[this](std::shared_ptr<const RsEvent> event)
{
rsEventsHandler(*event);
}, mRsEventsHandle ); // mRsEventsHandle is zeroed in initializer list
} }
@ -1284,11 +1276,6 @@ bool p3discovery2::setPeerVersion(const RsPeerId &peerId, const std::string &ver
return true; return true;
} }
void p3discovery2::rsEventsHandler(const RsEvent& event)
{
Dbg3() << __PRETTY_FUNCTION__ << " " << static_cast<uint32_t>(event.mType) << std::endl;
}
/*************************************************************************************/ /*************************************************************************************/
/* AuthGPGService */ /* AuthGPGService */

View File

@ -99,12 +99,10 @@ void RsGRouterGenericDataItem::serial_process(RsGenericSerializer::SerializeJob
RsTypeSerializer::serial_process (j,ctx,destination_key,"destination_key") ; RsTypeSerializer::serial_process (j,ctx,destination_key,"destination_key") ;
RsTypeSerializer::serial_process<uint32_t>(j,ctx,service_id,"service_id") ; RsTypeSerializer::serial_process<uint32_t>(j,ctx,service_id,"service_id") ;
RsTypeSerializer::TlvMemBlock_proxy prox(data_bytes,data_size) ; RsTypeSerializer::RawMemoryWrapper prox(data_bytes, data_size);
RsTypeSerializer::serial_process(j, ctx, prox, "data");
RsTypeSerializer::serial_process(j,ctx,prox,"data") ; if(!!(ctx.mFlags & RsSerializationFlags::SIGNATURE)) return;
if(ctx.mFlags & RsGenericSerializer::SERIALIZATION_FLAG_SIGNATURE)
return ;
RsTypeSerializer::serial_process<RsTlvItem>(j,ctx,signature,"signature") ; RsTypeSerializer::serial_process<RsTlvItem>(j,ctx,signature,"signature") ;
RsTypeSerializer::serial_process<uint32_t>(j,ctx,duplication_factor,"duplication_factor") ; RsTypeSerializer::serial_process<uint32_t>(j,ctx,duplication_factor,"duplication_factor") ;
@ -133,8 +131,7 @@ void RsGRouterSignedReceiptItem::serial_process(RsGenericSerializer::SerializeJo
RsTypeSerializer::serial_process<uint32_t> (j,ctx,service_id,"service_id") ; RsTypeSerializer::serial_process<uint32_t> (j,ctx,service_id,"service_id") ;
RsTypeSerializer::serial_process (j,ctx,data_hash,"data_hash") ; RsTypeSerializer::serial_process (j,ctx,data_hash,"data_hash") ;
if(ctx.mFlags & RsGenericSerializer::SERIALIZATION_FLAG_SIGNATURE) if(!!(ctx.mFlags & RsSerializationFlags::SIGNATURE)) return;
return ;
RsTypeSerializer::serial_process<RsTlvItem>(j,ctx,signature,"signature") ; RsTypeSerializer::serial_process<RsTlvItem>(j,ctx,signature,"signature") ;
} }

View File

@ -286,7 +286,9 @@ class RsGRouterRoutingInfoItem: public RsGRouterItem, public GRouterRoutingInfo,
class RsGRouterSerialiser: public RsServiceSerializer class RsGRouterSerialiser: public RsServiceSerializer
{ {
public: public:
explicit RsGRouterSerialiser(SerializationFlags flags = SERIALIZATION_FLAG_NONE) : RsServiceSerializer(RS_SERVICE_TYPE_GROUTER,RsGenericSerializer::FORMAT_BINARY,flags) {} explicit RsGRouterSerialiser(
RsSerializationFlags flags = RsSerializationFlags::NONE ):
RsServiceSerializer(RS_SERVICE_TYPE_GROUTER, flags) {}
virtual RsItem *create_item(uint16_t service,uint8_t subtype) const ; virtual RsItem *create_item(uint16_t service,uint8_t subtype) const ;
}; };

View File

@ -1658,7 +1658,9 @@ void p3GRouter::handleIncomingReceiptItem(const RsGRouterSignedReceiptItem *rece
Sha1CheckSum p3GRouter::computeDataItemHash(const RsGRouterGenericDataItem *data_item) Sha1CheckSum p3GRouter::computeDataItemHash(const RsGRouterGenericDataItem *data_item)
{ {
RsGRouterSerialiser signature_serializer(RsGenericSerializer::SERIALIZATION_FLAG_SIGNATURE | RsGenericSerializer::SERIALIZATION_FLAG_SKIP_HEADER); RsGRouterSerialiser signature_serializer(
RsSerializationFlags::SIGNATURE |
RsSerializationFlags::SKIP_HEADER );
uint32_t signed_data_size = signature_serializer.size(const_cast<RsGRouterGenericDataItem*>(data_item)); uint32_t signed_data_size = signature_serializer.size(const_cast<RsGRouterGenericDataItem*>(data_item));
uint32_t total_size = signed_data_size + data_item->signature.TlvSize() ; uint32_t total_size = signed_data_size + data_item->signature.TlvSize() ;
@ -2034,7 +2036,9 @@ bool p3GRouter::signDataItem(RsGRouterAbstractMsgItem *item,const RsGxsId& signi
std::cerr << " Key ID = " << signing_id << std::endl; std::cerr << " Key ID = " << signing_id << std::endl;
std::cerr << " Getting key material..." << std::endl; std::cerr << " Getting key material..." << std::endl;
//#endif //#endif
RsGRouterSerialiser signature_serializer(RsGenericSerializer::SERIALIZATION_FLAG_SIGNATURE | RsGenericSerializer::SERIALIZATION_FLAG_SKIP_HEADER) ; RsGRouterSerialiser signature_serializer(
RsSerializationFlags::SIGNATURE |
RsSerializationFlags::SKIP_HEADER );
uint32_t data_size = signature_serializer.size(item) ; uint32_t data_size = signature_serializer.size(item) ;
RsTemporaryMemory data(data_size) ; RsTemporaryMemory data(data_size) ;
@ -2092,8 +2096,8 @@ bool p3GRouter::verifySignedDataItem(const RsGRouterAbstractMsgItem *item,const
} }
RsGRouterSerialiser signature_serializer( RsGRouterSerialiser signature_serializer(
RsGenericSerializer::SERIALIZATION_FLAG_SIGNATURE | RsSerializationFlags::SIGNATURE |
RsGenericSerializer::SERIALIZATION_FLAG_SKIP_HEADER ); RsSerializationFlags::SKIP_HEADER );
uint32_t data_size = signature_serializer.size(const_cast<RsGRouterAbstractMsgItem*>(item)); // the const cast shouldn't be necessary if size() took a const. uint32_t data_size = signature_serializer.size(const_cast<RsGRouterAbstractMsgItem*>(item)); // the const cast shouldn't be necessary if size() took a const.
RsTemporaryMemory data(data_size); RsTemporaryMemory data(data_size);

View File

@ -1969,3 +1969,5 @@ bool RsGxsDataAccess::checkMsgFilter(
return true; return true;
} }
GxsGroupStatistic::~GxsGroupStatistic() = default;
GxsServiceStatistic::~GxsServiceStatistic() = default;

View File

@ -78,10 +78,10 @@ JsonApiServer::corsOptionsHeaders =
#define INITIALIZE_API_CALL_JSON_CONTEXT \ #define INITIALIZE_API_CALL_JSON_CONTEXT \
RsGenericSerializer::SerializeContext cReq( \ RsGenericSerializer::SerializeContext cReq( \
nullptr, 0, \ nullptr, 0, \
RsGenericSerializer::SERIALIZATION_FLAG_YIELDING ); \ RsSerializationFlags::YIELDING ); \
RsJson& jReq(cReq.mJson); \ RsJson& jReq(cReq.mJson); \
if(session->get_request()->get_method() == "GET") \ if(session->get_request()->get_method() == "GET") \
{ \ { \
const std::string jrqp(session->get_request()->get_query_parameter("jsonData")); \ const std::string jrqp(session->get_request()->get_query_parameter("jsonData")); \
jReq.Parse(jrqp.c_str(), jrqp.size()); \ jReq.Parse(jrqp.c_str(), jrqp.size()); \
} \ } \
@ -352,7 +352,7 @@ JsonApiServer::JsonApiServer(): configMutex("JsonApiServer config"),
rsEvents, "rsEvents", cAns, session ) ) rsEvents, "rsEvents", cAns, session ) )
return; return;
RsEventType eventType = RsEventType::NONE; RsEventType eventType = RsEventType::__NONE;
// deserialize input parameters from JSON // deserialize input parameters from JSON
{ {
@ -395,7 +395,8 @@ JsonApiServer::JsonApiServer(): configMutex("JsonApiServer config"),
} ); } );
}; };
bool retval = rsEvents->registerEventsHandler(eventType,multiCallback, hId); std::error_condition retval = rsEvents->registerEventsHandler(
multiCallback, hId, eventType );
{ {
RsGenericSerializer::SerializeContext& ctx(cAns); RsGenericSerializer::SerializeContext& ctx(cAns);

View File

@ -151,8 +151,6 @@ protected:
/// @see RsThread /// @see RsThread
void onStopRequested() override; void onStopRequested() override;
static const RsJsonApiErrorCategory sErrorCategory;
static std::error_condition badApiCredientalsFormat( static std::error_condition badApiCredientalsFormat(
const std::string& user, const std::string& passwd ); const std::string& user, const std::string& passwd );

View File

@ -45,7 +45,6 @@ file_lists {
file_sharing/directory_updater.h \ file_sharing/directory_updater.h \
file_sharing/rsfilelistitems.h \ file_sharing/rsfilelistitems.h \
file_sharing/dir_hierarchy.h \ file_sharing/dir_hierarchy.h \
file_sharing/file_tree.h \
file_sharing/file_sharing_defaults.h file_sharing/file_sharing_defaults.h
SOURCES *= file_sharing/p3filelists.cc \ SOURCES *= file_sharing/p3filelists.cc \
@ -481,6 +480,8 @@ HEADERS += util/folderiterator.h \
util/dnsresolver.h \ util/dnsresolver.h \
util/radix32.h \ util/radix32.h \
util/radix64.h \ util/radix64.h \
util/rsbase64.h \
util/rsendian.h \
util/rsinitedptr.h \ util/rsinitedptr.h \
util/rsprint.h \ util/rsprint.h \
util/rsstring.h \ util/rsstring.h \
@ -494,7 +495,8 @@ HEADERS += util/folderiterator.h \
util/rstime.h \ util/rstime.h \
util/stacktrace.h \ util/stacktrace.h \
util/rsdeprecate.h \ util/rsdeprecate.h \
util/cxx11retrocompat.h \ util/cxx11retrocompat.h \
util/cxx14retrocompat.h \
util/cxx17retrocompat.h \ util/cxx17retrocompat.h \
util/rsurl.h \ util/rsurl.h \
util/rserrno.h util/rserrno.h
@ -637,6 +639,7 @@ SOURCES += util/folderiterator.cc \
util/rsrecogn.cc \ util/rsrecogn.cc \
util/rstime.cc \ util/rstime.cc \
util/rsurl.cc \ util/rsurl.cc \
util/rsbase64.cc \
util/rserrno.cc util/rserrno.cc
equals(RS_UPNP_LIB, miniupnpc) { equals(RS_UPNP_LIB, miniupnpc) {

View File

@ -630,50 +630,61 @@ std::string PGPHandler::SaveCertificateToString(const RsPgpId& id,bool include_s
return makeRadixEncodedPGPKey(key,include_signatures) ; return makeRadixEncodedPGPKey(key,include_signatures) ;
} }
bool PGPHandler::exportPublicKey(const RsPgpId& id,unsigned char *& mem_block,size_t& mem_size,bool armoured,bool include_signatures) const bool PGPHandler::exportPublicKey(
const RsPgpId& id,
unsigned char*& mem_block, size_t& mem_size,
bool armoured, bool include_signatures ) const
{ {
RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. mem_block = nullptr; mem_size = 0; // clear just in case
const ops_keydata_t *key = locked_getPublicKey(id,false) ;
mem_block = NULL ;
if(armoured) if(armoured)
{ {
std::cerr << __PRETTY_FUNCTION__ << ": should not be used with armoured=true, because there's a bug in the armoured export of OPS" << std::endl; RsErr() << __PRETTY_FUNCTION__ << " should not be used with "
return false ; << "armoured=true, because there's a bug in the armoured export"
<< " of OPS" << std::endl;
print_stacktrace();
return false;
} }
if(key == NULL) RS_STACK_MUTEX(pgphandlerMtx);
const ops_keydata_t* key = locked_getPublicKey(id,false);
if(!key)
{ {
std::cerr << "Cannot output key " << id.toStdString() << ": not found in keyring." << std::endl; RsErr() << __PRETTY_FUNCTION__ << " key id: " << id
return false ; << " not found in keyring." << std::endl;
return false;
} }
ops_create_info_t* cinfo; ops_create_info_t* cinfo;
ops_memory_t *buf = NULL ; ops_memory_t *buf = nullptr;
ops_setup_memory_write(&cinfo, &buf, 0); ops_setup_memory_write(&cinfo, &buf, 0);
if(ops_write_transferable_public_key_from_packet_data(key,armoured,cinfo) != ops_true) if(ops_write_transferable_public_key_from_packet_data(
key, armoured, cinfo ) != ops_true)
{ {
std::cerr << "ERROR: This key cannot be processed by RetroShare because\nDSA certificates are not yet handled." << std::endl; RsErr() << __PRETTY_FUNCTION__ << " This key id " << id
return false ; << " cannot be processed by RetroShare because DSA certificates"
<< " support is not implemented yet." << std::endl;
return false;
} }
ops_writer_close(cinfo) ; ops_writer_close(cinfo);
mem_block = new unsigned char[ops_memory_get_length(buf)] ; mem_size = ops_memory_get_length(buf);
mem_size = ops_memory_get_length(buf) ; mem_block = reinterpret_cast<unsigned char*>(malloc(mem_size));
memcpy(mem_block,ops_memory_get_data(buf),mem_size) ; memcpy(mem_block,ops_memory_get_data(buf),mem_size);
ops_teardown_memory_write(cinfo,buf); ops_teardown_memory_write(cinfo,buf);
if(!include_signatures) if(!include_signatures)
{ {
size_t new_size ; size_t new_size;
PGPKeyManagement::findLengthOfMinimalKey(mem_block,mem_size,new_size) ; PGPKeyManagement::findLengthOfMinimalKey(mem_block, mem_size, new_size);
mem_size = new_size ; mem_size = new_size;
} }
return true ; return true;
} }
bool PGPHandler::exportGPGKeyPair(const std::string& filename,const RsPgpId& exported_key_id) const bool PGPHandler::exportGPGKeyPair(const std::string& filename,const RsPgpId& exported_key_id) const

View File

@ -107,7 +107,11 @@ public:
bool LoadCertificateFromBinaryData(const unsigned char *bin_data,uint32_t bin_data_len, RsPgpId& gpg_id, std::string& error_string); bool LoadCertificateFromBinaryData(const unsigned char *bin_data,uint32_t bin_data_len, RsPgpId& gpg_id, std::string& error_string);
std::string SaveCertificateToString(const RsPgpId& id,bool include_signatures) const ; std::string SaveCertificateToString(const RsPgpId& id,bool include_signatures) const ;
bool exportPublicKey(const RsPgpId& id,unsigned char *& mem,size_t& mem_size,bool armoured,bool include_signatures) const ;
/** The caller is in charge of freeing `mem` once finished */
bool exportPublicKey( const RsPgpId& id,
unsigned char*& mem, size_t& mem_size,
bool armoured, bool include_signatures) const;
bool parseSignature(unsigned char *sign, unsigned int signlen,RsPgpId& issuer_id) ; bool parseSignature(unsigned char *sign, unsigned int signlen,RsPgpId& issuer_id) ;
bool SignDataBin(const RsPgpId& id, const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen, bool make_raw_signature=false, std::string reason = "") ; bool SignDataBin(const RsPgpId& id, const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen, bool make_raw_signature=false, std::string reason = "") ;

View File

@ -3,7 +3,9 @@
* * * *
* libretroshare: retroshare core library * * libretroshare: retroshare core library *
* * * *
* Copyright (C) 2019 Gioacchino Mazzurco <gio@eigenlab.org> * * Copyright (C) 2019-2020 Retroshare Team <contact@retroshare.cc> *
* Copyright (C) 2019-2020 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2020 Asociación Civil Altermundi <info@altermundi.net> *
* * * *
* This program is free software: you can redistribute it and/or modify * * This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as * * it under the terms of the GNU Lesser General Public License as *
@ -50,7 +52,7 @@ extern RsEvents* rsEvents;
*/ */
enum class RsEventType : uint32_t enum class RsEventType : uint32_t
{ {
NONE = 0, /// Used to detect uninitialized event __NONE = 0, /// Used internally to detect invalid event type passed
/// @see RsBroadcastDiscovery /// @see RsBroadcastDiscovery
BROADCAST_DISCOVERY = 1, BROADCAST_DISCOVERY = 1,
@ -64,7 +66,7 @@ enum class RsEventType : uint32_t
/// @see pqissl /// @see pqissl
PEER_CONNECTION = 4, PEER_CONNECTION = 4,
/// @see RsGxsChanges // this one is used in RsGxsBroadcast /// @see RsGxsChanges, used also in @see RsGxsBroadcast
GXS_CHANGES = 5, GXS_CHANGES = 5,
/// Emitted when a peer state changes, @see RsPeers /// Emitted when a peer state changes, @see RsPeers
@ -95,11 +97,62 @@ enum class RsEventType : uint32_t
FILE_TRANSFER = 14, FILE_TRANSFER = 14,
/// @see RsMsgs /// @see RsMsgs
CHAT_MESSAGE = 15, CHAT_MESSAGE = 15,
MAX /// Used to detect invalid event type passed __MAX /// Used internally, keep last
}; };
enum class RsEventsErrorNum : int32_t
{
EVENT_TYPE_UNDEFINED = 3004,
EVENT_TYPE_OUT_OF_RANGE = 3005,
INVALID_HANDLER_ID = 3006,
NULL_EVENT_POINTER = 3007
};
struct RsEventsErrorCategory: std::error_category
{
const char* name() const noexcept override
{ return "RetroShare Events"; }
std::string message(int ev) const override
{
switch (static_cast<RsEventsErrorNum>(ev))
{
case RsEventsErrorNum::EVENT_TYPE_UNDEFINED:
return "Undefined event type";
case RsEventsErrorNum::EVENT_TYPE_OUT_OF_RANGE:
return "Event type out of range";
case RsEventsErrorNum::INVALID_HANDLER_ID:
return "Invalid handler id";
default:
return "Error message for error: " + std::to_string(ev) +
" not available in category: " + name();
}
}
std::error_condition default_error_condition(int ev) const noexcept override;
const static RsEventsErrorCategory instance;
};
namespace std
{
/** Register RsJsonApiErrorNum as an error condition enum, must be in std
* namespace */
template<> struct is_error_condition_enum<RsEventsErrorNum> : true_type {};
}
/** Provide RsEventsErrorNum conversion to std::error_condition, must be in
* same namespace of RsJsonApiErrorNum */
inline std::error_condition make_error_condition(RsEventsErrorNum e) noexcept
{
return std::error_condition(
static_cast<int>(e), RsEventsErrorCategory::instance );
};
/** /**
* This struct is not meant to be used directly, you should create events type * This struct is not meant to be used directly, you should create events type
* deriving from it. * deriving from it.
@ -107,7 +160,7 @@ enum class RsEventType : uint32_t
struct RsEvent : RsSerializable struct RsEvent : RsSerializable
{ {
protected: protected:
RsEvent(RsEventType type) : explicit RsEvent(RsEventType type) :
mType(type), mTimePoint(std::chrono::system_clock::now()) {} mType(type), mTimePoint(std::chrono::system_clock::now()) {}
RsEvent() = delete; RsEvent() = delete;
@ -144,12 +197,10 @@ public:
* @param[in] event * @param[in] event
* @param[out] errorMessage Optional storage for error messsage, meaningful * @param[out] errorMessage Optional storage for error messsage, meaningful
* only on failure. * only on failure.
* @return False on error, true otherwise. * @return Success or error details.
*/ */
virtual bool postEvent( virtual std::error_condition postEvent(
std::shared_ptr<const RsEvent> event, std::shared_ptr<const RsEvent> event ) = 0;
std::string& errorMessage = RS_DEFAULT_STORAGE_PARAM(std::string)
) = 0;
/** /**
* @brief Send event directly to handlers. Blocking API * @brief Send event directly to handlers. Blocking API
@ -157,12 +208,10 @@ public:
* @param[in] event * @param[in] event
* @param[out] errorMessage Optional storage for error messsage, meaningful * @param[out] errorMessage Optional storage for error messsage, meaningful
* only on failure. * only on failure.
* @return False on error, true otherwise. * @return Success or error details.
*/ */
virtual bool sendEvent( virtual std::error_condition sendEvent(
std::shared_ptr<const RsEvent> event, std::shared_ptr<const RsEvent> event ) = 0;
std::string& errorMessage = RS_DEFAULT_STORAGE_PARAM(std::string)
) = 0;
/** /**
* @brief Generate unique handler identifier * @brief Generate unique handler identifier
@ -174,8 +223,9 @@ public:
* @brief Register events handler * @brief Register events handler
* Every time an event is dispatced the registered events handlers will get * Every time an event is dispatced the registered events handlers will get
* their method handleEvent called with the event passed as paramether. * their method handleEvent called with the event passed as paramether.
* @attention Callbacks must not fiddle internally with methods of this
* class otherwise a deadlock will happen.
* @jsonapi{development,manualwrapper} * @jsonapi{development,manualwrapper}
* @param eventType Type of event for which the callback is called
* @param multiCallback Function that will be called each time an event * @param multiCallback Function that will be called each time an event
* is dispatched. * is dispatched.
* @param[inout] hId Optional storage for handler id, useful to * @param[inout] hId Optional storage for handler id, useful to
@ -183,21 +233,23 @@ public:
* value may be provided to the function call but * value may be provided to the function call but
* must habe been generated with * must habe been generated with
* @see generateUniqueHandlerId() * @see generateUniqueHandlerId()
* @return False on error, true otherwise. * @param[in] eventType Optional type of event for which the callback is
* called, if __NONE is passed multiCallback is
* called for every events without filtering.
* @return Success or error details.
*/ */
virtual bool registerEventsHandler( virtual std::error_condition registerEventsHandler(
RsEventType eventType,
std::function<void(std::shared_ptr<const RsEvent>)> multiCallback, std::function<void(std::shared_ptr<const RsEvent>)> multiCallback,
RsEventsHandlerId_t& hId = RS_DEFAULT_STORAGE_PARAM(RsEventsHandlerId_t, 0) RsEventsHandlerId_t& hId = RS_DEFAULT_STORAGE_PARAM(RsEventsHandlerId_t, 0),
) = 0; RsEventType eventType = RsEventType::__NONE ) = 0;
/** /**
* @brief Unregister event handler * @brief Unregister event handler
* @param[in] hId Id of the event handler to unregister * @param[in] hId Id of the event handler to unregister
* @return True if the handler id has been found, false otherwise. * @return Success or error details.
*/ */
virtual bool unregisterEventsHandler(RsEventsHandlerId_t hId) = 0; virtual std::error_condition unregisterEventsHandler(
RsEventsHandlerId_t hId ) = 0;
virtual ~RsEvents(); virtual ~RsEvents();
}; };

View File

@ -4,7 +4,8 @@
* libretroshare: retroshare core library * * libretroshare: retroshare core library *
* * * *
* Copyright (C) 2008 Robert Fernie <retroshare@lunamutt.com> * * Copyright (C) 2008 Robert Fernie <retroshare@lunamutt.com> *
* Copyright (C) 2018-2019 Gioacchino Mazzurco <gio@eigenlab.org> * * Copyright (C) 2018-2020 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2019-2020 Asociación Civil Altermundi <info@altermundi.net> *
* * * *
* This program is free software: you can redistribute it and/or modify * * This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as * * it under the terms of the GNU Lesser General Public License as *
@ -28,12 +29,14 @@
#include <functional> #include <functional>
#include <chrono> #include <chrono>
#include <cstdint> #include <cstdint>
#include <system_error>
#include "rstypes.h" #include "rstypes.h"
#include "serialiser/rsserializable.h" #include "serialiser/rsserializable.h"
#include "rsturtle.h" #include "rsturtle.h"
#include "util/rstime.h" #include "util/rstime.h"
#include "retroshare/rsevents.h" #include "retroshare/rsevents.h"
#include "util/rsmemory.h"
class RsFiles; class RsFiles;
@ -43,6 +46,50 @@ class RsFiles;
*/ */
extern RsFiles* rsFiles; extern RsFiles* rsFiles;
enum class RsFilesErrorNum : int32_t
{
FILES_HANDLE_NOT_FOUND = 2004,
};
struct RsFilesErrorCategory: std::error_category
{
const char* name() const noexcept override
{ return "RetroShare Files"; }
std::string message(int ev) const override
{
switch (static_cast<RsFilesErrorNum>(ev))
{
case RsFilesErrorNum::FILES_HANDLE_NOT_FOUND:
return "Files handle not found";
default:
return "Error message for error: " + std::to_string(ev) +
" not available in category: " + name();
}
}
std::error_condition default_error_condition(int ev) const noexcept override;
const static RsFilesErrorCategory instance;
};
namespace std
{
/** Register RsFilesErrorNum as an error condition enum, must be in std
* namespace */
template<> struct is_error_condition_enum<RsFilesErrorNum> : true_type {};
}
/** Provide RsJsonApiErrorNum conversion to std::error_condition, must be in
* same namespace of RsJsonApiErrorNum */
inline std::error_condition make_error_condition(RsFilesErrorNum e) noexcept
{
return std::error_condition(
static_cast<int>(e), RsFilesErrorCategory::instance );
};
namespace RsRegularExpression { class Expression; } namespace RsRegularExpression { class Expression; }
/* These are used mainly by ftController at the moment */ /* These are used mainly by ftController at the moment */
@ -96,8 +143,28 @@ const FileSearchFlags RS_FILE_HINTS_BROWSABLE ( 0x00000100 );// bro
const FileSearchFlags RS_FILE_HINTS_SEARCHABLE ( 0x00000200 );// can be searched anonymously const FileSearchFlags RS_FILE_HINTS_SEARCHABLE ( 0x00000200 );// can be searched anonymously
const FileSearchFlags RS_FILE_HINTS_PERMISSION_MASK ( 0x00000380 );// OR of the last tree flags. Used to filter out. const FileSearchFlags RS_FILE_HINTS_PERMISSION_MASK ( 0x00000380 );// OR of the last tree flags. Used to filter out.
// Flags used when requesting a transfer /** Flags used when requesting a new file transfer */
// enum class FileRequestFlags: uint32_t
{
/// Enable requesting file via turtle routing.
ANONYMOUS_ROUTING = 0x00000040,
/// Asks (TODO: or enforce?) for end-to-end encryption of file trasfer
ENCRYPTED = 0x00000080,
/// Asks (TODO: or enforce?) no end-to-end encryption of file trasfer
UNENCRYPTED = 0x00000100,
/// Start trasfer very slow
SLOW = 0x00002000,
/// Disable searching for potential direct sources
NO_DIRECT_SEARCH = 0x02000000
};
RS_REGISTER_ENUM_FLAGS_TYPE(FileRequestFlags)
/// @deprecated Flags used when requesting a transfer
/// @see FileRequestFlags instead
const TransferRequestFlags RS_FILE_REQ_ANONYMOUS_ROUTING ( 0x00000040 ); // Use to ask turtle router to download the file. const TransferRequestFlags RS_FILE_REQ_ANONYMOUS_ROUTING ( 0x00000040 ); // Use to ask turtle router to download the file.
const TransferRequestFlags RS_FILE_REQ_ENCRYPTED ( 0x00000080 ); // Asks for end-to-end encryption of file at the level of ftServer const TransferRequestFlags RS_FILE_REQ_ENCRYPTED ( 0x00000080 ); // Asks for end-to-end encryption of file at the level of ftServer
const TransferRequestFlags RS_FILE_REQ_UNENCRYPTED ( 0x00000100 ); // Asks for no end-to-end encryption of file at the level of ftServer const TransferRequestFlags RS_FILE_REQ_UNENCRYPTED ( 0x00000100 ); // Asks for no end-to-end encryption of file at the level of ftServer
@ -111,10 +178,6 @@ const TransferRequestFlags RS_FILE_REQ_NO_SEARCH ( 0x02000000 ); // di
// const uint32_t RS_FILE_HINTS_SHARE_FLAGS_MASK = RS_FILE_HINTS_NETWORK_WIDE_OTHERS | RS_FILE_HINTS_BROWSABLE_OTHERS // const uint32_t RS_FILE_HINTS_SHARE_FLAGS_MASK = RS_FILE_HINTS_NETWORK_WIDE_OTHERS | RS_FILE_HINTS_BROWSABLE_OTHERS
// | RS_FILE_HINTS_NETWORK_WIDE_GROUPS | RS_FILE_HINTS_BROWSABLE_GROUPS ; // | RS_FILE_HINTS_NETWORK_WIDE_GROUPS | RS_FILE_HINTS_BROWSABLE_GROUPS ;
/* Callback Codes */
const uint32_t RS_FILE_EXTRA_DELETE = 0x0010;
enum class RsSharedDirectoriesEventCode: uint8_t { enum class RsSharedDirectoriesEventCode: uint8_t {
UNKNOWN = 0x00, UNKNOWN = 0x00,
STARTING_DIRECTORY_SWEEP = 0x01, // (void) STARTING_DIRECTORY_SWEEP = 0x01, // (void)
@ -202,36 +265,117 @@ struct SharedDirStats
uint64_t total_shared_size ; uint64_t total_shared_size ;
}; };
// This class represents a tree of directories and files, only with their names size and hash. It is used to create collection links in the GUI /** This class represents a tree of directories and files, only with their names
// and to transmit directory information between services. This class is independent from the existing FileHierarchy classes used in storage because * size and hash. It is used to create collection links in the GUI and to
// we need a very copact serialization and storage size since we create links with it. Besides, we cannot afford to risk the leak of other local information * transmit directory information between services. This class is independent
// by using the orignal classes. * from the existing FileHierarchy classes used in storage because we need a
* very copact serialization and storage size since we create links with it.
class FileTree * Besides, we cannot afford to risk the leak of other local information
* by using the orignal classes.
*/
struct RsFileTree : RsSerializable
{ {
public: public:
virtual ~FileTree() {} RsFileTree() : mTotalFiles(0), mTotalSize(0) {}
static FileTree *create(const DirDetails& dd, bool remote, bool remove_top_dirs = true) ; /**
static FileTree *create(const std::string& radix64_string) ; * @brief Create a RsFileTree from directory details
* @param dd directory or file details
* @param remote
* @param remove_top_dirs
* @return pointer to the created file-tree
*/
static std::unique_ptr<RsFileTree> fromDirDetails(
const DirDetails& dd, bool remote, bool remove_top_dirs = true );
virtual std::string toRadix64() const =0 ; /**
* @brief Create a RsFileTree from Base64 representation
* @param base64 base64 or base64url string representation of the file-tree
* @return pointer to the parsed file-tree on success, nullptr plus error
* details on failure
*/
static std::tuple<std::unique_ptr<RsFileTree>, std::error_condition>
fromBase64(const std::string& base64);
// These methods allow the user to browse the hierarchy /** @brief Convert to base64 representetion */
std::string toBase64() const;
struct FileData { /// @see RsSerializable
std::string name ; virtual void serial_process(
uint64_t size ; RsGenericSerializer::SerializeJob j,
RsFileHash hash ; RsGenericSerializer::SerializeContext& ctx )
{
RS_SERIAL_PROCESS(mFiles);
RS_SERIAL_PROCESS(mDirs);
RS_SERIAL_PROCESS(mTotalFiles);
RS_SERIAL_PROCESS(mTotalSize);
}
struct FileData: RsSerializable
{
std::string name;
uint64_t size;
RsFileHash hash;
void serial_process(
RsGenericSerializer::SerializeJob j,
RsGenericSerializer::SerializeContext& ctx ) override;
}; };
virtual uint32_t root() const { return 0;} /// Allow browsing the hierarchy
virtual bool getDirectoryContent(uint32_t index,std::string& name,std::vector<uint32_t>& subdirs,std::vector<FileData>& subfiles) const = 0; bool getDirectoryContent(
std::string& name, std::vector<uint64_t>& subdirs,
std::vector<FileData>& subfiles, uint64_t handle = 0 ) const;
virtual void print() const=0; struct DirData: RsSerializable
{
std::string name;
std::vector<uint64_t> subdirs;
std::vector<uint64_t> subfiles;
uint32_t mTotalFiles ; void serial_process(
uint64_t mTotalSize ; RsGenericSerializer::SerializeJob j,
RsGenericSerializer::SerializeContext& ctx ) override;
};
static void recurs_buildFileTree(
RsFileTree& ft, uint32_t index, const DirDetails& dd, bool remote,
bool remove_top_dirs );
std::vector<FileData> mFiles;
std::vector<DirData> mDirs;
uint32_t mTotalFiles;
uint64_t mTotalSize;
virtual ~RsFileTree();
/**
* @brief Create a RsFileTree from Radix64 representation
* @deprecated kept for retrocompatibility with RetroShare-gui
* The format is not compatible with the new methods
* @param radix64_string
* @return nullptr if on failure, pointer to the created FileTree on success
*/
RS_DEPRECATED_FOR(fromBase64)
static std::unique_ptr<RsFileTree> fromRadix64(
const std::string& radix64_string );
/** @brief Convert to radix64 representetion
* @deprecated kept for retrocompatibility with RetroShare-gui
* The format is not compatible with the new methods
*/
RS_DEPRECATED_FOR(toBase64)
std::string toRadix64() const;
private:
/** @deprecated kept for retrocompatibility with RetroShare-gui */
RS_DEPRECATED_FOR(serial_process)
bool serialise(unsigned char *& data,uint32_t& data_size) const;
/** @deprecated kept for retrocompatibility with RetroShare-gui */
RS_DEPRECATED_FOR(serial_process)
bool deserialise(unsigned char* data, uint32_t data_size);
}; };
struct BannedFileEntry : RsSerializable struct BannedFileEntry : RsSerializable
@ -258,12 +402,12 @@ struct TurtleFileInfoV2 : RsSerializable
{ {
TurtleFileInfoV2() : fSize(0), fWeight(0) {} TurtleFileInfoV2() : fSize(0), fWeight(0) {}
TurtleFileInfoV2(const TurtleFileInfo& oldInfo) : explicit TurtleFileInfoV2(const TurtleFileInfo& oldInfo) :
fSize(oldInfo.size), fHash(oldInfo.hash), fName(oldInfo.name), fSize(oldInfo.size), fHash(oldInfo.hash), fName(oldInfo.name),
fWeight(0) {} fWeight(0) {}
#ifdef RS_DEEP_FILES_INDEX #ifdef RS_DEEP_FILES_INDEX
TurtleFileInfoV2(const DeepFilesSearchResult& dRes); explicit TurtleFileInfoV2(const DeepFilesSearchResult& dRes);
#endif // def RS_DEEP_FILES_INDEX #endif // def RS_DEEP_FILES_INDEX
uint64_t fSize; /// File size uint64_t fSize; /// File size
@ -301,9 +445,6 @@ struct TurtleFileInfoV2 : RsSerializable
class RsFiles class RsFiles
{ {
public: public:
RsFiles() {}
virtual ~RsFiles() {}
/** /**
* @brief Provides file data for the GUI, media streaming or API clients. * @brief Provides file data for the GUI, media streaming or API clients.
* It may return unverified chunks. This allows streaming without having to * It may return unverified chunks. This allows streaming without having to
@ -344,10 +485,10 @@ public:
/** /**
* @brief Initiate downloading of a file * @brief Initiate downloading of a file
* @jsonapi{development} * @jsonapi{development}
* @param[in] fileName * @param[in] fileName file name
* @param[in] hash * @param[in] hash file hash
* @param[in] size * @param[in] size file size
* @param[in] destPath in not empty specify a destination path * @param[in] destPath optional specify the destination directory
* @param[in] flags you usually want RS_FILE_REQ_ANONYMOUS_ROUTING * @param[in] flags you usually want RS_FILE_REQ_ANONYMOUS_ROUTING
* @param[in] srcIds eventually specify known sources * @param[in] srcIds eventually specify known sources
* @return false if we already have the file, true otherwhise * @return false if we already have the file, true otherwhise
@ -357,6 +498,25 @@ public:
const std::string& destPath, TransferRequestFlags flags, const std::string& destPath, TransferRequestFlags flags,
const std::list<RsPeerId>& srcIds ) = 0; const std::list<RsPeerId>& srcIds ) = 0;
/**
* @brief Initiate download of a files collection
* @jsonapi{development}
* An usually useful companion method of this is @see parseFilesLink()
* @param[in] collection collection of files to download
* @param[in] destPath optional base path on which to download the
* collection, if left empty the default download directory will be used
* @param[in] srcIds optional peers id known as direct source of the
* collection
* @param[in] flags optional flags to fine tune search and download
* algorithm
* @return success or error details.
*/
virtual std::error_condition requestFiles(
const RsFileTree& collection,
const std::string& destPath = "",
const std::vector<RsPeerId>& srcIds = std::vector<RsPeerId>(),
FileRequestFlags flags = FileRequestFlags::ANONYMOUS_ROUTING ) = 0;
/** /**
* @brief Cancel file downloading * @brief Cancel file downloading
* @jsonapi{development} * @jsonapi{development}
@ -575,7 +735,7 @@ public:
* @return false if error occurred, true otherwise * @return false if error occurred, true otherwise
*/ */
virtual bool requestDirDetails( virtual bool requestDirDetails(
DirDetails &details, std::uintptr_t handle = 0, DirDetails &details, uint64_t handle = 0,
FileSearchFlags flags = RS_FILE_HINTS_LOCAL ) = 0; FileSearchFlags flags = RS_FILE_HINTS_LOCAL ) = 0;
/*** /***
@ -584,8 +744,9 @@ public:
/** /**
* Kept for retrocompatibility, it was originally written for easier * Kept for retrocompatibility, it was originally written for easier
* interaction with Qt. As soon as you can, you should prefer to use the * interaction with Qt. As soon as you can, you should prefer to use the
* version of this methodn which take `std::uintptr_t handle` as paramether. * version of this method which take `uint64_t handle` as paramether.
*/ */
RS_DEPRECATED_FOR(requestDirDetails)
virtual int RequestDirDetails( virtual int RequestDirDetails(
void* handle, DirDetails& details, FileSearchFlags flags ) = 0; void* handle, DirDetails& details, FileSearchFlags flags ) = 0;
@ -726,6 +887,76 @@ public:
*/ */
virtual bool removeSharedDirectory(std::string dir) = 0; virtual bool removeSharedDirectory(std::string dir) = 0;
/// Default base URL used for files links @see exportFilesLink
static const std::string DEFAULT_FILES_BASE_URL;
/** Link query field used to store collection files count
* @see exportFilesLink */
static const std::string FILES_URL_COUNT_FIELD;
/// Link query field used to store collection data @see exportFilesLink
static const std::string FILES_URL_DATA_FIELD;
/** Link query FILES_URL_DATA_FIELD field value used to instruct the parser
* to look for the data into the link fragment
* @see exportFilesLink and parseFilesLink */
static const std::string FILES_URL_FAGMENT_FORWARD;
/// Link query field used to store collection name @see exportFilesLink
static const std::string FILES_URL_NAME_FIELD;
/// Link query field used to store collection size @see exportFilesLink
static const std::string FILES_URL_SIZE_FIELD;
/**
* @brief Export link to a collection of files
* @jsonapi{development}
* @param[out] link storage for the generated link
* @param[in] handle directory RetroShare handle
* @param[in] fragSneak when true the file data is sneaked into fragment
* instead of FILES_URL_DATA_FIELD query field, this way if using an
* http[s] link to pass around a disguised file link a misconfigured host
* attempting to visit that link with a web browser will not send the file
* data to the server thus protecting at least some of the privacy of the
* user even in a misconfiguration scenario.
* @param[in] baseUrl URL into which to sneak in the RetroShare file link
* base64, this is primarly useful to induce applications into making the
* link clickable, or to disguise the RetroShare link into a "normal"
* looking web link. If empty the collection data link will be outputted in
* plain base64 format.
* @return error information if some error occurred, 0/SUCCESS otherwise
*/
virtual std::error_condition exportCollectionLink(
std::string& link, uint64_t handle, bool fragSneak = false,
const std::string& baseUrl = RsFiles::DEFAULT_FILES_BASE_URL ) = 0;
/**
* @brief Export link to a file
* @jsonapi{development}
* @param[out] link @see exportCollectionLink
* @param[in] fileHash hash of the file
* @param[in] fileSize size of the file
* @param[in] fileName name of the file
* @param[in] fragSneak @see exportCollectionLink
* @param[in] baseUrl @see exportCollectionLink
* @return error @see exportCollectionLink
*/
virtual std::error_condition exportFileLink(
std::string& link, const RsFileHash& fileHash, uint64_t fileSize,
const std::string& fileName, bool fragSneak = false,
const std::string& baseUrl = RsFiles::DEFAULT_FILES_BASE_URL ) = 0;
/**
* @brief Parse RetroShare files link
* @jsonapi{development}
* Support also old RetroShare-gui file and collections links format.
* @param[in] link files link either in base64 or URL format
* @param[out] collection storage for parsed files link
* @return error information if some error occurred, 0/SUCCESS otherwise
*/
virtual std::error_condition parseFilesLink(
const std::string& link, RsFileTree& collection ) = 0;
/** /**
* @brief Get list of ignored file name prefixes and suffixes * @brief Get list of ignored file name prefixes and suffixes
* @param[out] ignoredPrefixes storage for ingored prefixes * @param[out] ignoredPrefixes storage for ingored prefixes
@ -757,4 +988,6 @@ public:
virtual bool ignoreDuplicates() = 0; virtual bool ignoreDuplicates() = 0;
virtual void setIgnoreDuplicates(bool ignore) = 0; virtual void setIgnoreDuplicates(bool ignore) = 0;
virtual ~RsFiles() = default;
}; };

View File

@ -24,6 +24,7 @@
#include <type_traits> #include <type_traits>
#include <ostream> #include <ostream>
#include <bitset>
/** Check if given type is a scoped enum */ /** Check if given type is a scoped enum */
template<typename E> template<typename E>
@ -128,13 +129,7 @@ typename std::enable_if<Rs__BitFlagsOps<EFT>::enabled, std::ostream>::type&
operator <<(std::ostream& stream, EFT flags) operator <<(std::ostream& stream, EFT flags)
{ {
using u_t = typename std::underlying_type<EFT>::type; using u_t = typename std::underlying_type<EFT>::type;
return stream << std::bitset<sizeof(u_t)>(static_cast<u_t>(flags));
for(int i = sizeof(u_t); i>=0; --i)
{
stream << (flags & ( 1 << i ) ? "1" : "0");
if( i % 8 == 0 ) stream << " ";
}
return stream;
} }
#include <cstdint> #include <cstdint>
@ -170,6 +165,7 @@ template<int n> class RS_DEPRECATED_FOR(RS_REGISTER_ENUM_FLAGS_TYPE) t_RsFlags32
inline t_RsFlags32() : _bits(0) {} inline t_RsFlags32() : _bits(0) {}
inline explicit t_RsFlags32(uint32_t N) : _bits(N) {} // allows initialization from a set of uint32_t inline explicit t_RsFlags32(uint32_t N) : _bits(N) {} // allows initialization from a set of uint32_t
inline t_RsFlags32<n> operator| (const t_RsFlags32<n>& f) const { return t_RsFlags32<n>(_bits | f._bits) ; } inline t_RsFlags32<n> operator| (const t_RsFlags32<n>& f) const { return t_RsFlags32<n>(_bits | f._bits) ; }
inline t_RsFlags32<n> operator^ (const t_RsFlags32<n>& f) const { return t_RsFlags32<n>(_bits ^ f._bits) ; } inline t_RsFlags32<n> operator^ (const t_RsFlags32<n>& f) const { return t_RsFlags32<n>(_bits ^ f._bits) ; }
inline t_RsFlags32<n> operator* (const t_RsFlags32<n>& f) const { return t_RsFlags32<n>(_bits & f._bits) ; } inline t_RsFlags32<n> operator* (const t_RsFlags32<n>& f) const { return t_RsFlags32<n>(_bits & f._bits) ; }
@ -187,6 +183,19 @@ template<int n> class RS_DEPRECATED_FOR(RS_REGISTER_ENUM_FLAGS_TYPE) t_RsFlags32
//inline explicit operator bool() const { return _bits>0; } //inline explicit operator bool() const { return _bits>0; }
inline uint32_t toUInt32() const { return _bits ; } inline uint32_t toUInt32() const { return _bits ; }
/// Easier porting to new flag system
template<typename EFT> inline
typename std::enable_if<(Rs__BitFlagsOps<EFT>::enabled &&
sizeof(EFT) >= sizeof(uint32_t) ), EFT>::type
toEFT() { return static_cast<EFT>(_bits); }
/// Easier porting to new flag system
template<typename EFT>
static inline typename std::enable_if<
Rs__BitFlagsOps<EFT>::enabled &&
sizeof(EFT) <= sizeof(uint32_t), t_RsFlags32>::type
fromEFT(EFT e) { return t_RsFlags32(static_cast<uint32_t>(e)); }
void clear() { _bits = 0 ; } void clear() { _bits = 0 ; }
friend std::ostream& operator<<(std::ostream& o,const t_RsFlags32<n>& f) // friendly print with 0 and I friend std::ostream& operator<<(std::ostream& o,const t_RsFlags32<n>& f) // friendly print with 0 and I
@ -199,8 +208,10 @@ template<int n> class RS_DEPRECATED_FOR(RS_REGISTER_ENUM_FLAGS_TYPE) t_RsFlags32
} }
return o ; return o ;
} }
private:
uint32_t _bits ; private:
friend struct RsTypeSerializer;
uint32_t _bits;
}; };
#define FLAGS_TAG_TRANSFER_REQS 0x4228af #define FLAGS_TAG_TRANSFER_REQS 0x4228af
@ -210,9 +221,9 @@ template<int n> class RS_DEPRECATED_FOR(RS_REGISTER_ENUM_FLAGS_TYPE) t_RsFlags32
#define FLAGS_TAG_SERVICE_CHAT 0x839042 #define FLAGS_TAG_SERVICE_CHAT 0x839042
#define FLAGS_TAG_SERIALIZER 0xa0338d #define FLAGS_TAG_SERIALIZER 0xa0338d
// Flags for requesting transfers, ask for turtle, cache, speed, etc. /// @deprecated Flags for requesting transfers, ask for turtle, cache, speed, etc.
// RS_DEPRECATED_FOR(FileRequestFlags)
typedef t_RsFlags32<FLAGS_TAG_TRANSFER_REQS> TransferRequestFlags ; typedef t_RsFlags32<FLAGS_TAG_TRANSFER_REQS> TransferRequestFlags;
// Flags for file storage. Mainly permissions like BROWSABLE/NETWORK_WIDE for groups and peers. // Flags for file storage. Mainly permissions like BROWSABLE/NETWORK_WIDE for groups and peers.
// //
@ -230,7 +241,3 @@ typedef t_RsFlags32<FLAGS_TAG_SERVICE_PERM > ServicePermissionFlags ;
// //
typedef t_RsFlags32<FLAGS_TAG_SERVICE_CHAT > ChatLobbyFlags ; typedef t_RsFlags32<FLAGS_TAG_SERVICE_CHAT > ChatLobbyFlags ;
// Flags for serializer
//
typedef t_RsFlags32<FLAGS_TAG_SERIALIZER > SerializationFlags ;

View File

@ -4,7 +4,8 @@
* libretroshare: retroshare core library * * libretroshare: retroshare core library *
* * * *
* Copyright (C) 2012 Robert Fernie <retroshare@lunamutt.com> * * Copyright (C) 2012 Robert Fernie <retroshare@lunamutt.com> *
* Copyright (C) 2018-2019 Gioacchino Mazzurco <gio@eigenlab.org> * * Copyright (C) 2018-2020 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2019-2020 Asociación Civil Altermundi <info@altermundi.net> *
* * * *
* This program is free software: you can redistribute it and/or modify * * This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as * * it under the terms of the GNU Lesser General Public License as *
@ -283,26 +284,6 @@ public:
*/ */
virtual bool ExtraFileRemove(const RsFileHash& hash) = 0; virtual bool ExtraFileRemove(const RsFileHash& hash) = 0;
/**
* @brief Get auto-download option value for given channel
* @jsonapi{development}
* @param[in] channelId channel id
* @param[out] enabled storage for the auto-download option value
* @return false if something failed, true otherwhise
*/
virtual bool getChannelAutoDownload(
const RsGxsGroupId& channelId, bool& enabled ) = 0;
/**
* @brief Get download directory for the given channel
* @jsonapi{development}
* @param[in] channelId id of the channel
* @param[out] directory reference to string where to store the path
* @return false on error, true otherwise
*/
virtual bool getChannelDownloadDirectory( const RsGxsGroupId& channelId,
std::string& directory ) = 0;
/** /**
* @brief Get channels summaries list. Blocking API. * @brief Get channels summaries list. Blocking API.
* @jsonapi{development} * @jsonapi{development}
@ -331,13 +312,15 @@ public:
* @param[out] comments storage for the comments * @param[out] comments storage for the comments
* @return false if something failed, true otherwhise * @return false if something failed, true otherwhise
*/ */
virtual bool getChannelAllContent(const RsGxsGroupId& channelId, virtual bool getChannelAllContent( const RsGxsGroupId& channelId,
std::vector<RsGxsChannelPost>& posts, std::vector<RsGxsChannelPost>& posts,
std::vector<RsGxsComment>& comments ) = 0; std::vector<RsGxsComment>& comments ) = 0;
/** /**
* @brief Get channel messages and comments corresponding to the given message ID list. If the list is empty, nothing is returned. Since * @brief Get channel messages and comments corresponding to the given IDs.
* comments are themselves messages, it is possible to get comments only by only supplying their message IDs. * If the set is empty, nothing is returned.
* @note Since comments are internally themselves messages, it is possible
* to get comments only by supplying their IDs.
* @jsonapi{development} * @jsonapi{development}
* @param[in] channelId id of the channel of which the content is requested * @param[in] channelId id of the channel of which the content is requested
* @param[in] contentsIds ids of requested contents * @param[in] contentsIds ids of requested contents
@ -345,8 +328,8 @@ public:
* @param[out] comments storage for the comments * @param[out] comments storage for the comments
* @return false if something failed, true otherwhise * @return false if something failed, true otherwhise
*/ */
virtual bool getChannelContent(const RsGxsGroupId& channelId, virtual bool getChannelContent( const RsGxsGroupId& channelId,
const std::set<RsGxsMessageId>& contentIds, const std::set<RsGxsMessageId>& contentsIds,
std::vector<RsGxsChannelPost>& posts, std::vector<RsGxsChannelPost>& posts,
std::vector<RsGxsComment>& comments ) = 0; std::vector<RsGxsComment>& comments ) = 0;
@ -369,16 +352,6 @@ public:
*/ */
virtual bool markRead(const RsGxsGrpMsgIdPair& postId, bool read) = 0; virtual bool markRead(const RsGxsGrpMsgIdPair& postId, bool read) = 0;
/**
* @brief Enable or disable auto-download for given channel. Blocking API
* @jsonapi{development}
* @param[in] channelId channel id
* @param[in] enable true to enable, false to disable
* @return false if something failed, true otherwhise
*/
virtual bool setChannelAutoDownload(
const RsGxsGroupId& channelId, bool enable ) = 0;
/** /**
* @brief Share channel publishing key * @brief Share channel publishing key
* This can be used to authorize other peers to post on the channel * This can be used to authorize other peers to post on the channel
@ -390,16 +363,6 @@ public:
virtual bool shareChannelKeys( virtual bool shareChannelKeys(
const RsGxsGroupId& channelId, const std::set<RsPeerId>& peers ) = 0; const RsGxsGroupId& channelId, const std::set<RsPeerId>& peers ) = 0;
/**
* @brief Set download directory for the given channel. Blocking API.
* @jsonapi{development}
* @param[in] channelId id of the channel
* @param[in] directory path
* @return false on error, true otherwise
*/
virtual bool setChannelDownloadDirectory(
const RsGxsGroupId& channelId, const std::string& directory) = 0;
/** /**
* @brief Subscrbe to a channel. Blocking API * @brief Subscrbe to a channel. Blocking API
* @jsonapi{development} * @jsonapi{development}
@ -525,8 +488,62 @@ public:
std::string& errMsg = RS_DEFAULT_STORAGE_PARAM(std::string) ) = 0; std::string& errMsg = RS_DEFAULT_STORAGE_PARAM(std::string) ) = 0;
/* Following functions are deprecated as they expose internal functioning /* Following functions are deprecated and should not be considered a safe to
* semantic, instead of a safe to use API */ * use API */
/**
* @brief Get auto-download option value for given channel
* @jsonapi{development}
* @deprecated This feature rely on very buggy code, the returned value is
* not reliable @see setChannelAutoDownload().
* @param[in] channelId channel id
* @param[out] enabled storage for the auto-download option value
* @return false if something failed, true otherwhise
*/
RS_DEPRECATED
virtual bool getChannelAutoDownload(
const RsGxsGroupId& channelId, bool& enabled ) = 0;
/**
* @brief Enable or disable auto-download for given channel. Blocking API
* @jsonapi{development}
* @deprecated This feature rely on very buggy code, when enabled the
* channel service start flooding erratically log with error messages,
* apparently without more dangerous consequences. Still those messages
* hints that something out of control is happening under the hood, use at
* your own risk. A safe alternative to this method can easly implemented
* at API client level instead.
* @param[in] channelId channel id
* @param[in] enable true to enable, false to disable
* @return false if something failed, true otherwhise
*/
RS_DEPRECATED
virtual bool setChannelAutoDownload(
const RsGxsGroupId& channelId, bool enable ) = 0;
/**
* @brief Get download directory for the given channel
* @jsonapi{development}
* @deprecated @see setChannelAutoDownload()
* @param[in] channelId id of the channel
* @param[out] directory reference to string where to store the path
* @return false on error, true otherwise
*/
RS_DEPRECATED
virtual bool getChannelDownloadDirectory( const RsGxsGroupId& channelId,
std::string& directory ) = 0;
/**
* @brief Set download directory for the given channel. Blocking API.
* @jsonapi{development}
* @deprecated @see setChannelAutoDownload()
* @param[in] channelId id of the channel
* @param[in] directory path
* @return false on error, true otherwise
*/
RS_DEPRECATED
virtual bool setChannelDownloadDirectory(
const RsGxsGroupId& channelId, const std::string& directory) = 0;
/** /**
* @brief Create channel. Blocking API. * @brief Create channel. Blocking API.

View File

@ -305,10 +305,10 @@ public:
static const std::string FORUM_URL_DATA_FIELD; static const std::string FORUM_URL_DATA_FIELD;
/** Link query field used to store forum message title /** Link query field used to store forum message title
* @see exportChannelLink */ * @see exportForumLink */
static const std::string FORUM_URL_MSG_TITLE_FIELD; static const std::string FORUM_URL_MSG_TITLE_FIELD;
/// Link query field used to store forum message id @see exportChannelLink /// Link query field used to store forum message id @see exportForumLink
static const std::string FORUM_URL_MSG_ID_FIELD; static const std::string FORUM_URL_MSG_ID_FIELD;
/** /**

View File

@ -3,8 +3,8 @@
* * * *
* libretroshare: retroshare core library * * libretroshare: retroshare core library *
* * * *
* Copyright 2011 by Christopher Evi-Parker * * Copyright (C) 2011 Christopher Evi-Parker *
* Copyright (C) 2018-2019 Gioacchino Mazzurco <gio@eigenlab.org> * * Copyright (C) 2018-2020 Gioacchino Mazzurco <gio@eigenlab.org> *
* * * *
* This program is free software: you can redistribute it and/or modify * * This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as * * it under the terms of the GNU Lesser General Public License as *
@ -30,6 +30,7 @@
#include "retroshare/rsreputations.h" #include "retroshare/rsreputations.h"
#include "rsgxsflags.h" #include "rsgxsflags.h"
#include "util/rsdeprecate.h" #include "util/rsdeprecate.h"
#include "util/rsdebug.h"
/*! /*!
* This class only make method of internal members visible tu upper level to * This class only make method of internal members visible tu upper level to
@ -46,7 +47,7 @@
enum class TokenRequestType: uint8_t enum class TokenRequestType: uint8_t
{ {
UNDEFINED = 0x00, __NONE = 0x00, /// Used to detect uninitialized
GROUP_DATA = 0x01, GROUP_DATA = 0x01,
GROUP_META = 0x02, GROUP_META = 0x02,
POSTS = 0x03, POSTS = 0x03,
@ -55,6 +56,7 @@ enum class TokenRequestType: uint8_t
GROUP_STATISTICS = 0x06, GROUP_STATISTICS = 0x06,
SERVICE_STATISTICS = 0x07, SERVICE_STATISTICS = 0x07,
NO_KILL_TYPE = 0x08, NO_KILL_TYPE = 0x08,
__MAX /// Used to detect out of range
}; };
class RsGxsIfaceHelper class RsGxsIfaceHelper
@ -64,10 +66,11 @@ public:
* @param gxs handle to RsGenExchange instance of service (Usually the * @param gxs handle to RsGenExchange instance of service (Usually the
* service class itself) * service class itself)
*/ */
RsGxsIfaceHelper(RsGxsIface& gxs) : explicit RsGxsIfaceHelper(RsGxsIface& gxs) :
mGxs(gxs), mTokenService(*gxs.getTokenService()),mMtx("GxsIfaceHelper") {} mGxs(gxs), mTokenService(*gxs.getTokenService()), mMtx("GxsIfaceHelper")
{}
~RsGxsIfaceHelper(){} ~RsGxsIfaceHelper() = default;
/*! /*!
* Gxs services should call this for automatic handling of * Gxs services should call this for automatic handling of
@ -444,9 +447,9 @@ protected:
uint32_t token, uint32_t token,
std::chrono::milliseconds maxWait = std::chrono::milliseconds(20000), std::chrono::milliseconds maxWait = std::chrono::milliseconds(20000),
std::chrono::milliseconds checkEvery = std::chrono::milliseconds(100), std::chrono::milliseconds checkEvery = std::chrono::milliseconds(100),
bool auto_delete_if_unsuccessful=true) bool auto_delete_if_unsuccessful=true)
{ {
#if defined(__ANDROID__) && (__ANDROID_API__ < 24) #if defined(__ANDROID__) && (__ANDROID_API__ < 24)
auto wkStartime = std::chrono::steady_clock::now(); auto wkStartime = std::chrono::steady_clock::now();
int maxWorkAroundCnt = 10; int maxWorkAroundCnt = 10;
LLwaitTokenBeginLabel: LLwaitTokenBeginLabel:
@ -454,13 +457,14 @@ LLwaitTokenBeginLabel:
auto timeout = std::chrono::steady_clock::now() + maxWait; auto timeout = std::chrono::steady_clock::now() + maxWait;
auto st = requestStatus(token); auto st = requestStatus(token);
while( !(st == RsTokenService::FAILED || st >= RsTokenService::COMPLETE) && std::chrono::steady_clock::now() < timeout ) while( !(st == RsTokenService::FAILED || st >= RsTokenService::COMPLETE)
&& std::chrono::steady_clock::now() < timeout )
{ {
std::this_thread::sleep_for(checkEvery); std::this_thread::sleep_for(checkEvery);
st = requestStatus(token); st = requestStatus(token);
} }
if(st != RsTokenService::COMPLETE && auto_delete_if_unsuccessful) if(st != RsTokenService::COMPLETE && auto_delete_if_unsuccessful)
cancelRequest(token); cancelRequest(token);
#if defined(__ANDROID__) && (__ANDROID_API__ < 24) #if defined(__ANDROID__) && (__ANDROID_API__ < 24)
/* Work around for very slow/old android devices, we don't expect this /* Work around for very slow/old android devices, we don't expect this
@ -487,35 +491,39 @@ LLwaitTokenBeginLabel:
#endif #endif
{ {
RS_STACK_MUTEX(mMtx); RS_STACK_MUTEX(mMtx);
mActiveTokens.erase(token); mActiveTokens.erase(token);
} }
return st; return st;
} }
private: private:
RsGxsIface& mGxs; RsGxsIface& mGxs;
RsTokenService& mTokenService; RsTokenService& mTokenService;
RsMutex mMtx; RsMutex mMtx;
std::map<uint32_t,TokenRequestType> mActiveTokens; std::map<uint32_t,TokenRequestType> mActiveTokens;
void locked_dumpTokens() void locked_dumpTokens()
{ {
uint16_t service_id = mGxs.serviceType(); const uint16_t service_id = mGxs.serviceType();
const auto countSize = static_cast<size_t>(TokenRequestType::__MAX);
uint32_t count[countSize] = {0};
uint32_t count[7] = {0}; RsDbg() << __PRETTY_FUNCTION__ << "Service 0x" << std::hex << service_id
<< " (" << rsServiceControl->getServiceName(
RsServiceInfo::RsServiceInfoUIn16ToFullServiceId(service_id) )
<< ") this=0x" << static_cast<void*>(this)
<< ") Active tokens (per type): ";
RsDbg() << "Service " << std::hex << service_id << std::dec // let's count how many token of each type we've got.
<< " (" << rsServiceControl->getServiceName(RsServiceInfo::RsServiceInfoUIn16ToFullServiceId(service_id)) for(auto& it: mActiveTokens) ++count[static_cast<size_t>(it.second)];
<< ") this=" << std::hex << (void*)this << std::dec << ") Active tokens (per type): " ;
for(auto& it: mActiveTokens) // let's count how many token of each type we've got. for(uint32_t i=0; i < countSize; ++i)
++count[static_cast<int>(it.second)]; RsDbg().uStream() /* << i << ":" */ << count[i] << " ";
RsDbg().uStream() << std::endl;
}
for(uint32_t i=0;i<7;++i) RS_SET_CONTEXT_DEBUG_LEVEL(1)
std::cerr << std::dec /* << i << ":" */ << count[i] << " ";
std::cerr << std::endl;
}
}; };

View File

@ -193,55 +193,50 @@ struct RsMsgMetaData : RsSerializable
struct RsGxsGenericMsgData struct RsGxsGenericMsgData
{ {
virtual ~RsGxsGenericMsgData() = default; // making the type polymorphic virtual ~RsGxsGenericMsgData() = default; // making the type polymorphic
RsMsgMetaData mMeta; RsMsgMetaData mMeta;
}; };
class GxsGroupStatistic struct GxsGroupStatistic : RsSerializable
{ {
public: GxsGroupStatistic() :
GxsGroupStatistic() mNumMsgs(0), mTotalSizeOfMsgs(0), mNumThreadMsgsNew(0),
mNumThreadMsgsUnread(0), mNumChildMsgsNew(0), mNumChildMsgsUnread(0) {}
/// @see RsSerializable
void serial_process( RsGenericSerializer::SerializeJob j,
RsGenericSerializer::SerializeContext& ctx ) override
{ {
mNumMsgs = 0; RS_SERIAL_PROCESS(mGrpId);
mTotalSizeOfMsgs = 0; RS_SERIAL_PROCESS(mNumMsgs);
mNumThreadMsgsNew = 0; RS_SERIAL_PROCESS(mTotalSizeOfMsgs);
mNumThreadMsgsUnread = 0; RS_SERIAL_PROCESS(mNumThreadMsgsNew);
mNumChildMsgsNew = 0; RS_SERIAL_PROCESS(mNumThreadMsgsUnread);
mNumChildMsgsUnread = 0; RS_SERIAL_PROCESS(mNumChildMsgsNew);
RS_SERIAL_PROCESS(mNumChildMsgsUnread);
} }
public: RsGxsGroupId mGrpId;
/// number of message uint32_t mNumMsgs; /// number of message, from the database
RsGxsGroupId mGrpId;
uint32_t mNumMsgs; // from the database
uint32_t mTotalSizeOfMsgs; uint32_t mTotalSizeOfMsgs;
uint32_t mNumThreadMsgsNew; uint32_t mNumThreadMsgsNew;
uint32_t mNumThreadMsgsUnread; uint32_t mNumThreadMsgsUnread;
uint32_t mNumChildMsgsNew; uint32_t mNumChildMsgsNew;
uint32_t mNumChildMsgsUnread; uint32_t mNumChildMsgsUnread;
~GxsGroupStatistic() override;
}; };
class GxsServiceStatistic struct GxsServiceStatistic : RsSerializable
{ {
public: GxsServiceStatistic() :
GxsServiceStatistic() mNumMsgs(0), mNumGrps(0), mSizeOfMsgs(0), mSizeOfGrps(0),
{ mNumGrpsSubscribed(0), mNumThreadMsgsNew(0), mNumThreadMsgsUnread(0),
mNumMsgs = 0; mNumChildMsgsNew(0), mNumChildMsgsUnread(0), mSizeStore(0) {}
mNumGrps = 0;
mSizeOfMsgs = 0;
mSizeOfGrps = 0;
mNumGrpsSubscribed = 0;
mNumThreadMsgsNew = 0;
mNumThreadMsgsUnread = 0;
mNumChildMsgsNew = 0;
mNumChildMsgsUnread = 0;
mSizeStore = 0;
}
public:
uint32_t mNumMsgs; uint32_t mNumMsgs;
uint32_t mNumGrps; uint32_t mNumGrps;
uint32_t mSizeOfMsgs; uint32_t mSizeOfMsgs;
@ -252,32 +247,35 @@ public:
uint32_t mNumChildMsgsNew; uint32_t mNumChildMsgsNew;
uint32_t mNumChildMsgsUnread; uint32_t mNumChildMsgsUnread;
uint32_t mSizeStore; uint32_t mSizeStore;
/// @see RsSerializable
void serial_process( RsGenericSerializer::SerializeJob j,
RsGenericSerializer::SerializeContext& ctx ) override
{
RS_SERIAL_PROCESS(mNumMsgs);
RS_SERIAL_PROCESS(mNumGrps);
RS_SERIAL_PROCESS(mSizeOfMsgs);
RS_SERIAL_PROCESS(mSizeOfGrps);
RS_SERIAL_PROCESS(mNumGrpsSubscribed);
RS_SERIAL_PROCESS(mNumThreadMsgsNew);
RS_SERIAL_PROCESS(mNumThreadMsgsUnread);
RS_SERIAL_PROCESS(mNumChildMsgsNew);
RS_SERIAL_PROCESS(mNumChildMsgsUnread);
RS_SERIAL_PROCESS(mSizeStore);
}
~GxsServiceStatistic() override;
}; };
class UpdateItem class RS_DEPRECATED RsGxsGroupUpdateMeta
{
public:
virtual ~UpdateItem() { }
};
class StringUpdateItem : public UpdateItem
{
public:
StringUpdateItem(const std::string update) : mUpdate(update) {}
const std::string& getUpdate() const { return mUpdate; }
private:
std::string mUpdate;
};
class RsGxsGroupUpdateMeta
{ {
public: public:
// expand as support is added for other utypes // expand as support is added for other utypes
enum UpdateType { DESCRIPTION, NAME }; enum UpdateType { DESCRIPTION, NAME };
RsGxsGroupUpdateMeta(const RsGxsGroupId& groupId) : mGroupId(groupId) {} explicit RsGxsGroupUpdateMeta(const RsGxsGroupId& groupId):
mGroupId(groupId) {}
typedef std::map<UpdateType, std::string> GxsMetaUpdate; typedef std::map<UpdateType, std::string> GxsMetaUpdate;

View File

@ -37,7 +37,7 @@
#include "serialiser/rstypeserializer.h" #include "serialiser/rstypeserializer.h"
#include "util/rsdeprecate.h" #include "util/rsdeprecate.h"
struct RsIdentity; class RsIdentity;
/** /**
* Pointer to global instance of RsIdentity service implementation * Pointer to global instance of RsIdentity service implementation

View File

@ -1,7 +1,7 @@
/* /*
* RetroShare JSON API public header * RetroShare JSON API public header
* *
* Copyright (C) 2018-2020 Gioacchino Mazzurco <gio.eigenlab.org> * Copyright (C) 2018-2020 Gioacchino Mazzurco <gio@eigenlab.org>
* Copyright (C) 2019 Cyril Soler <csoler@users.sourceforge.net> * Copyright (C) 2019 Cyril Soler <csoler@users.sourceforge.net>
* Copyright (C) 2020 Asociación Civil Altermundi <info@altermundi.net> * Copyright (C) 2020 Asociación Civil Altermundi <info@altermundi.net>
* *

View File

@ -3,7 +3,9 @@
* * * *
* libretroshare: retroshare core library * * libretroshare: retroshare core library *
* * * *
* Copyright 2004-2008 by Robert Fernie <retroshare@lunamutt.com> * * Copyright (C) 2004-2008 by Robert Fernie <retroshare@lunamutt.com> *
* Copyright (C) 2018-2020 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2020 Asociación Civil Altermundi <info@altermundi.net> *
* * * *
* This program is free software: you can redistribute it and/or modify * * This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as * * it under the terms of the GNU Lesser General Public License as *
@ -468,7 +470,7 @@ struct RsGroupInfo : RsSerializable
struct RsPeerStateChangedEvent : RsEvent struct RsPeerStateChangedEvent : RsEvent
{ {
/// @param[in] sslId is of the peer which changed state /// @param[in] sslId is of the peer which changed state
RsPeerStateChangedEvent(RsPeerId sslId); explicit RsPeerStateChangedEvent(RsPeerId sslId);
/// Storage fot the id of the peer that changed state /// Storage fot the id of the peer that changed state
RsPeerId mSslId; RsPeerId mSslId;
@ -605,7 +607,15 @@ public:
virtual bool getAssociatedSSLIds(const RsPgpId& gpg_id, std::list<RsPeerId>& ids) = 0; virtual bool getAssociatedSSLIds(const RsPgpId& gpg_id, std::list<RsPeerId>& ids) = 0;
virtual bool gpgSignData(const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen, std::string reason = "") = 0; virtual bool gpgSignData(const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen, std::string reason = "") = 0;
virtual RsPgpId pgpIdFromFingerprint(const RsPgpFingerprint& fpr) = 0; /**
* @brief Convert PGP fingerprint to PGP id
* @jsonapi{development}
* Helper method useful while we port the whole RetroShare codebase from
* RsPgpId to RsPgpFingerprint
* @param[in] fpr PGP fingerprint to convert
* @return PGP id corresponding to the fingerprint
*/
virtual RsPgpId pgpIdFromFingerprint(const RsPgpFingerprint& fpr) = 0;
// Note: the two methods below could be unified. The fact that one of them can take an optional RsPeerDetails struct as parameter // Note: the two methods below could be unified. The fact that one of them can take an optional RsPeerDetails struct as parameter
// seems quite inconsistent. // seems quite inconsistent.
@ -803,7 +813,7 @@ public:
ServicePermissionFlags flags = RS_NODE_PERM_DEFAULT ) = 0; ServicePermissionFlags flags = RS_NODE_PERM_DEFAULT ) = 0;
/* Auth Stuff */ RS_DEPRECATED /// This function doesn't provide meaningful error reporting
virtual std::string getPGPKey(const RsPgpId& pgp_id,bool include_signatures) = 0; virtual std::string getPGPKey(const RsPgpId& pgp_id,bool include_signatures) = 0;
virtual bool GetPGPBase64StringAndCheckSum(const RsPgpId& gpg_id,std::string& gpg_base64_string,std::string& gpg_base64_checksum) = 0; virtual bool GetPGPBase64StringAndCheckSum(const RsPgpId& gpg_id,std::string& gpg_base64_string,std::string& gpg_base64_checksum) = 0;

View File

@ -201,7 +201,8 @@ struct FileInfo : RsSerializable
std::string path; std::string path;
std::string fname; std::string fname;
RsFileHash hash; RsFileHash hash;
std::string ext;
RS_DEPRECATED std::string ext; /// @deprecated unused
uint64_t size; uint64_t size;
uint64_t avail; /// how much we have uint64_t avail; /// how much we have
@ -303,10 +304,16 @@ struct DirDetails : RsSerializable
type(DIR_TYPE_UNKNOWN), count(0), mtime(0), max_mtime(0) {} type(DIR_TYPE_UNKNOWN), count(0), mtime(0), max_mtime(0) {}
/* G10h4ck do we still need to keep this as void* instead of uint64_t for
* retroshare-gui sake? */
void* parent; void* parent;
int prow; /* parent row */ int prow; /* parent row */
/* G10h4ck do we still need to keep this as void* instead of uint64_t for
* retroshare-gui sake? */
void* ref; void* ref;
uint8_t type; uint8_t type;
RsPeerId id; RsPeerId id;
std::string name; std::string name;
@ -322,36 +329,18 @@ struct DirDetails : RsSerializable
/// @see RsSerializable /// @see RsSerializable
void serial_process(RsGenericSerializer::SerializeJob j, void serial_process(RsGenericSerializer::SerializeJob j,
RsGenericSerializer::SerializeContext& ctx) RsGenericSerializer::SerializeContext& ctx) override
{ {
#if defined(__GNUC__) && !defined(__clang__) /* Enforce serialization as uint64_t because void* changes size
# pragma GCC diagnostic ignored "-Wstrict-aliasing" * depending (usually 4 bytes on 32bit arch and 8 bytes on 64bit archs)
#endif // defined(__GNUC__) && !defined(__clang__) */
uint64_t handle = reinterpret_cast<uint64_t>(ref);
RS_SERIAL_PROCESS(handle);
ref = reinterpret_cast<void*>(handle);
// (Cyril) We have to do this because on some systems (MacOS) uintptr_t is unsigned long which is not well defined. It is always uint64_t parentHandle = reinterpret_cast<uint64_t>(parent);
// preferable to force type serialization to the correct size rather than letting the compiler choose for us. RS_SERIAL_PROCESS(parentHandle);
// /!\ This structure cannot be sent over the network. The serialization would be inconsistent. parent = reinterpret_cast<void*>(parentHandle);
if(sizeof(ref) == 4)
{
std::uint32_t& handle(reinterpret_cast<std::uint32_t&>(ref));
RS_SERIAL_PROCESS(handle);
std::uint32_t& parentHandle(reinterpret_cast<std::uint32_t&>(parent));
RS_SERIAL_PROCESS(parentHandle);
}
else if(sizeof(ref) == 8)
{
std::uint64_t& handle(reinterpret_cast<std::uint64_t&>(ref));
RS_SERIAL_PROCESS(handle);
std::uint64_t& parentHandle(reinterpret_cast<std::uint64_t&>(parent));
RS_SERIAL_PROCESS(parentHandle);
}
else
std::cerr << __PRETTY_FUNCTION__ << ": cannot serialize raw pointer of size " << sizeof(ref) << std::endl;
#if defined(__GNUC__) && !defined(__clang__)
# pragma GCC diagnostic pop
#endif // defined(__GNUC__) && !defined(__clang__)
RS_SERIAL_PROCESS(prow); RS_SERIAL_PROCESS(prow);
RS_SERIAL_PROCESS(type); RS_SERIAL_PROCESS(type);
@ -366,6 +355,8 @@ struct DirDetails : RsSerializable
RS_SERIAL_PROCESS(children); RS_SERIAL_PROCESS(children);
RS_SERIAL_PROCESS(parent_groups); RS_SERIAL_PROCESS(parent_groups);
} }
~DirDetails() override = default;
}; };
class FileDetail class FileDetail

View File

@ -45,11 +45,12 @@ struct RsItem : RsMemoryManagement::SmallObject, RsSerializable
/// TODO: Do this make sense with the new serialization system? /// TODO: Do this make sense with the new serialization system?
virtual void clear() = 0; virtual void clear() = 0;
/// @deprecated use << ostream operator instead
RS_DEPRECATED_FOR("<< ostream operator")
virtual std::ostream &print(std::ostream &out, uint16_t /* indent */ = 0) virtual std::ostream &print(std::ostream &out, uint16_t /* indent */ = 0)
{ {
RsGenericSerializer::SerializeContext ctx( RsGenericSerializer::SerializeContext ctx(
NULL, 0, RsGenericSerializer::FORMAT_BINARY, nullptr, 0, RsSerializationFlags::NONE );
RsGenericSerializer::SERIALIZATION_FLAG_NONE );
serial_process(RsGenericSerializer::PRINT,ctx); serial_process(RsGenericSerializer::PRINT,ctx);
return out; return out;
} }

View File

@ -147,8 +147,8 @@ void RsMsgItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSeri
RsTypeSerializer::serial_process<RsTlvItem>(j,ctx,attachment,"attachment"); RsTypeSerializer::serial_process<RsTlvItem>(j,ctx,attachment,"attachment");
if(ctx.mFlags & RsServiceSerializer::SERIALIZATION_FLAG_CONFIG) if(!!(ctx.mFlags & RsSerializationFlags::CONFIG))
RsTypeSerializer::serial_process<uint32_t>(j,ctx,msgId,"msgId"); RS_SERIAL_PROCESS(msgId);
} }
void RsMsgTagType::clear() void RsMsgTagType::clear()

View File

@ -19,8 +19,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * * along with this program. If not, see <https://www.gnu.org/licenses/>. *
* * * *
*******************************************************************************/ *******************************************************************************/
#ifndef RS_MSG_ITEMS_H #pragma once
#define RS_MSG_ITEMS_H
#include <map> #include <map>
@ -33,10 +32,6 @@
#include "serialiser/rstlvfileitem.h" #include "serialiser/rstlvfileitem.h"
#include "grouter/grouteritems.h" #include "grouter/grouteritems.h"
#if 0
#include "serialiser/rstlvtypes.h"
#include "serialiser/rstlvfileitem.h"
#endif
/**************************************************************************/ /**************************************************************************/
@ -218,17 +213,12 @@ class RsMsgParentId : public RsMessageItem
class RsMsgSerialiser: public RsServiceSerializer class RsMsgSerialiser: public RsServiceSerializer
{ {
public: public:
RsMsgSerialiser(SerializationFlags flags = RsServiceSerializer::SERIALIZATION_FLAG_NONE) RsMsgSerialiser(
:RsServiceSerializer(RS_SERVICE_TYPE_MSG,RsGenericSerializer::FORMAT_BINARY,flags){} RsSerializationFlags flags = RsSerializationFlags::NONE ):
RsServiceSerializer(RS_SERVICE_TYPE_MSG, flags){}
virtual ~RsMsgSerialiser() {} RsItem* create_item(uint16_t service,uint8_t type) const override;
virtual RsItem *create_item(uint16_t service,uint8_t type) const ; ~RsMsgSerialiser() override = default;
}; };
/**************************************************************************/
#endif /* RS_MSG_ITEMS_H */

View File

@ -3,8 +3,9 @@
* * * *
* libretroshare: retroshare core library * * libretroshare: retroshare core library *
* * * *
* Copyright 2004-2008 by Robert Fernie <retroshare@lunamutt.com> * * Copyright (C) 2004-2008 Robert Fernie <retroshare@lunamutt.com> *
* Copyright (C) 2015-2018 Gioacchino Mazzurco <gio@eigenlab.org> * * Copyright (C) 2015-2020 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2020 Asociación Civil Altermundi <info@altermundi.net> *
* * * *
* This program is free software: you can redistribute it and/or modify * * This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as * * it under the terms of the GNU Lesser General Public License as *
@ -20,7 +21,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * * along with this program. If not, see <https://www.gnu.org/licenses/>. *
* * * *
*******************************************************************************/ *******************************************************************************/
#include "util/radix64.h"
#include "pgp/pgpkeyutil.h" #include "pgp/pgpkeyutil.h"
#include "rsserver/p3peers.h" #include "rsserver/p3peers.h"
@ -35,7 +36,8 @@
#include "retroshare/rsinit.h" #include "retroshare/rsinit.h"
#include "retroshare/rsfiles.h" #include "retroshare/rsfiles.h"
#include "util/rsurl.h" #include "util/rsurl.h"
#include "util/radix64.h"
#include "util/rsbase64.h"
#include "pgp/rscertificate.h" #include "pgp/rscertificate.h"
#include <iostream> #include <iostream>
@ -1095,51 +1097,59 @@ bool p3Peers::setProxyServer(const uint32_t type, const std::string &addr_str, c
std::string p3Peers::getPGPKey(const RsPgpId& pgp_id,bool include_signatures) std::string p3Peers::getPGPKey(const RsPgpId& pgp_id,bool include_signatures)
{ {
unsigned char *mem_block = NULL; rs_owner_ptr<unsigned char> mem_block = nullptr;
size_t mem_block_size = 0; size_t mem_block_size = 0;
if( !AuthGPG::getAuthGPG()->exportPublicKey( if( !AuthGPG::getAuthGPG()->exportPublicKey(
RsPgpId(pgp_id), mem_block, mem_block_size, RsPgpId(pgp_id), mem_block, mem_block_size,
false, include_signatures ) ) false, include_signatures ) )
{ {
std::cerr << "Cannot output certificate for id \"" << pgp_id RsErr() << __PRETTY_FUNCTION__
<< "\". Sorry." << std::endl; << " Failure retriving certificate for id " << pgp_id
return "" ; << std::endl;
return "";
} }
RsPeerDetails Detail; RsPeerDetails details;
if(!getGPGDetails(pgp_id,Detail)) return ""; if(!getGPGDetails(pgp_id, details)) return "";
RsCertificate cert( Detail,mem_block,mem_block_size ); auto certPtr =
delete[] mem_block ; RsCertificate::fromMemoryBlock(details, mem_block, mem_block_size);
return cert.armouredPGPKey(); free(mem_block);
if(certPtr) return certPtr->armouredPGPKey();
return "";
} }
bool p3Peers::GetPGPBase64StringAndCheckSum( const RsPgpId& gpg_id, bool p3Peers::GetPGPBase64StringAndCheckSum(
std::string& gpg_base64_string, const RsPgpId& gpg_id,
std::string& gpg_base64_checksum) std::string& gpg_base64_string, std::string& gpg_base64_checksum )
{ {
gpg_base64_string = "" ; gpg_base64_string = "" ;
gpg_base64_checksum = "" ; gpg_base64_checksum = "" ;
unsigned char *mem_block ; rs_owner_ptr<unsigned char> mem_block = nullptr;
size_t mem_block_size ; size_t mem_block_size = 0;
if(!AuthGPG::getAuthGPG()->exportPublicKey(
gpg_id,mem_block,mem_block_size,false,false ))
return false;
if(!AuthGPG::getAuthGPG()->exportPublicKey(gpg_id,mem_block,mem_block_size,false,false)) RsBase64::encode(mem_block, mem_block_size, gpg_base64_string, true, false);
return false ;
Radix64::encode(mem_block,mem_block_size,gpg_base64_string) ; uint32_t crc = PGPKeyManagement::compute24bitsCRC(mem_block,mem_block_size);
uint32_t crc = PGPKeyManagement::compute24bitsCRC((unsigned char *)mem_block,mem_block_size) ; free(mem_block);
unsigned char tmp[3] = { uint8_t((crc >> 16) & 0xff), uint8_t((crc >> 8) & 0xff), uint8_t(crc & 0xff) } ; unsigned char tmp[3] = {
Radix64::encode(tmp,3,gpg_base64_checksum) ; uint8_t((crc >> 16) & 0xff),
uint8_t((crc >> 8) & 0xff),
uint8_t(crc & 0xff) } ;
RsBase64::encode(tmp, 3, gpg_base64_checksum, true, false);
delete[] mem_block ; return true;
return true ;
} }
enum class RsShortInviteFieldType : uint8_t enum class RsShortInviteFieldType : uint8_t

View File

@ -141,7 +141,8 @@ public:
virtual std::string GetRetroshareInvite( virtual std::string GetRetroshareInvite(
const RsPeerId& ssl_id = RsPeerId(), const RsPeerId& ssl_id = RsPeerId(),
bool include_signatures = false, bool includeExtraLocators = true ); bool include_signatures = false, bool includeExtraLocators = true );
virtual std::string getPGPKey(const RsPgpId& pgp_id,bool include_signatures); RS_DEPRECATED /// @see RsPeers
std::string getPGPKey(const RsPgpId& pgp_id,bool include_signatures) override;
virtual bool GetPGPBase64StringAndCheckSum(const RsPgpId& gpg_id,std::string& gpg_base64_string,std::string& gpg_base64_checksum); virtual bool GetPGPBase64StringAndCheckSum(const RsPgpId& gpg_id,std::string& gpg_base64_string,std::string& gpg_base64_checksum);

View File

@ -125,9 +125,7 @@ RsItem::RsItem(uint8_t ver, uint8_t cls, uint8_t t, uint8_t subtype)
type = (ver << 24) + (cls << 16) + (t << 8) + subtype; type = (ver << 24) + (cls << 16) + (t << 8) + subtype;
} }
RsItem::~RsItem() RsItem::~RsItem() = default;
{
}
void RsItem::print_string(std::string &out, uint16_t indent) void RsItem::print_string(std::string &out, uint16_t indent)
{ {
@ -243,10 +241,7 @@ uint32_t RsSerialType::PacketId() const
RsSerialiser::RsSerialiser() RsSerialiser::RsSerialiser() = default;
{
return;
}
RsSerialiser::~RsSerialiser() RsSerialiser::~RsSerialiser()
@ -559,17 +554,7 @@ std::ostream &RsRawItem::print(std::ostream &out, uint16_t indent)
return out; return out;
} }
uint32_t getRsPktMaxSize() { return RsSerialiser::MAX_SERIAL_SIZE; }
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() uint32_t getRsPktBaseSize()
{ {

View File

@ -19,16 +19,16 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * * along with this program. If not, see <https://www.gnu.org/licenses/>. *
* * * *
*******************************************************************************/ *******************************************************************************/
#ifndef RS_BASE_SERIALISER_H #pragma once
#define RS_BASE_SERIALISER_H
#include <stdlib.h> #include <cstring>
#include <string.h>
#include <map> #include <map>
#include <string> #include <string>
#include <iosfwd> #include <iosfwd>
#include <stdlib.h> #include <cstdlib>
#include <stdint.h> #include <cstdint>
#include "util/rsdeprecate.h"
/******************************************************************* /*******************************************************************
* This is the Top-Level serialiser/deserialise, * This is the Top-Level serialiser/deserialise,
@ -66,7 +66,11 @@ class RsSerialType ;
class RsSerialiser class RsSerialiser
{ {
public: public:
/** Remember that every pqistreamer allocates an input buffer of this size!
* So don't make it too big! */
static constexpr uint32_t MAX_SERIAL_SIZE = 262143; /* 2^18 -1 */
RsSerialiser(); RsSerialiser();
~RsSerialiser(); ~RsSerialiser();
bool addSerialType(RsSerialType *type); bool addSerialType(RsSerialType *type);
@ -76,7 +80,7 @@ class RsSerialiser
RsItem * deserialise(void *data, uint32_t *size); RsItem * deserialise(void *data, uint32_t *size);
private: private:
std::map<uint32_t, RsSerialType *> serialisers; std::map<uint32_t, RsSerialType *> serialisers;
}; };
@ -95,6 +99,8 @@ uint16_t getRsItemService(uint32_t type);
/* size constants */ /* size constants */
uint32_t getRsPktBaseSize(); uint32_t getRsPktBaseSize();
RS_DEPRECATED_FOR(RsSerialiser::MAX_SERIAL_SIZE)
uint32_t getRsPktMaxSize(); uint32_t getRsPktMaxSize();
@ -106,5 +112,3 @@ std::ostream &printRsItemEnd(std::ostream &o, std::string n, uint16_t i);
/* defined in rstlvtypes.cc - redeclared here for ease */ /* defined in rstlvtypes.cc - redeclared here for ease */
std::ostream &printIndent(std::ostream &out, uint16_t indent); std::ostream &printIndent(std::ostream &out, uint16_t indent);
/* Wrapper class for data that is serialised somewhere else */ /* Wrapper class for data that is serialised somewhere else */
#endif /* RS_BASE_SERIALISER_H */

View File

@ -4,6 +4,8 @@
* libretroshare: retroshare core library * * libretroshare: retroshare core library *
* * * *
* Copyright (C) 2016 Cyril Soler <csoler@users.sourceforge.net> * * Copyright (C) 2016 Cyril Soler <csoler@users.sourceforge.net> *
* Copyright (C) 2020 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2020 Asociación Civil Altermundi <info@altermundi.net> *
* * * *
* This program is free software: you can redistribute it and/or modify * * This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as * * it under the terms of the GNU Lesser General Public License as *
@ -18,23 +20,17 @@
* You should have received a copy of the GNU Lesser General Public License * * 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/>. * * along with this program. If not, see <https://www.gnu.org/licenses/>. *
* * * *
*******************************************************************************/ ******************************************************************************/
#include <typeinfo> #include <typeinfo>
#include "rsitems/rsitem.h" #include "rsitems/rsitem.h"
#include "util/rsprint.h" #include "util/rsprint.h"
#include "serialiser/rsserializer.h" #include "serialiser/rsserializer.h"
#include "serialiser/rstypeserializer.h" #include "serialiser/rstypeserializer.h"
#include "util/stacktrace.h" #include "util/stacktrace.h"
#include "util/rsdebug.h" #include "util/rsdebug.h"
const SerializationFlags RsGenericSerializer::SERIALIZATION_FLAG_NONE ( 0x0000 );
const SerializationFlags RsGenericSerializer::SERIALIZATION_FLAG_CONFIG ( 0x0001 );
const SerializationFlags RsGenericSerializer::SERIALIZATION_FLAG_SIGNATURE ( 0x0002 );
const SerializationFlags RsGenericSerializer::SERIALIZATION_FLAG_SKIP_HEADER ( 0x0004 );
const SerializationFlags RsGenericSerializer::SERIALIZATION_FLAG_YIELDING ( 0x0008 );
RsItem *RsServiceSerializer::deserialise(void *data, uint32_t *size) RsItem *RsServiceSerializer::deserialise(void *data, uint32_t *size)
{ {
if(!data || !size || !*size) if(!data || !size || !*size)
@ -47,11 +43,13 @@ RsItem *RsServiceSerializer::deserialise(void *data, uint32_t *size)
return nullptr; return nullptr;
} }
if(mFlags & SERIALIZATION_FLAG_SKIP_HEADER) if(!!(mFlags & RsSerializationFlags::SKIP_HEADER))
{ {
std::cerr << "(EE) Cannot deserialise item with flags SERIALIZATION_FLAG_SKIP_HEADER. Check your code!" << std::endl; RsErr() << __PRETTY_FUNCTION__ << " Cannot deserialise item with flag "
return NULL ; << "SKIP_HEADER. Check your code!" << std::endl;
} print_stacktrace();
return nullptr;
}
uint32_t rstype = getRsItemId(const_cast<void*>((const void*)data)) ; uint32_t rstype = getRsItemId(const_cast<void*>((const void*)data)) ;
@ -64,7 +62,9 @@ RsItem *RsServiceSerializer::deserialise(void *data, uint32_t *size)
return NULL ; return NULL ;
} }
SerializeContext ctx(const_cast<uint8_t*>(static_cast<uint8_t*>(data)),*size,mFormat,mFlags); SerializeContext ctx(
const_cast<uint8_t*>(static_cast<uint8_t*>(data)), *size,
mFlags );
ctx.mOffset = 8 ; ctx.mOffset = 8 ;
item->serial_process(RsGenericSerializer::DESERIALIZE, ctx) ; item->serial_process(RsGenericSerializer::DESERIALIZE, ctx) ;
@ -85,11 +85,13 @@ RsItem *RsServiceSerializer::deserialise(void *data, uint32_t *size)
} }
RsItem *RsConfigSerializer::deserialise(void *data, uint32_t *size) RsItem *RsConfigSerializer::deserialise(void *data, uint32_t *size)
{ {
if(mFlags & SERIALIZATION_FLAG_SKIP_HEADER) if(!!(mFlags & RsSerializationFlags::SKIP_HEADER))
{ {
std::cerr << "(EE) Cannot deserialise item with flags SERIALIZATION_FLAG_SKIP_HEADER. Check your code!" << std::endl; RsErr() << __PRETTY_FUNCTION__ << " Cannot deserialise item with flag "
return NULL ; << "SKIP_HEADER. Check your code!" << std::endl;
} print_stacktrace();
return nullptr;
}
uint32_t rstype = getRsItemId(const_cast<void*>((const void*)data)) ; uint32_t rstype = getRsItemId(const_cast<void*>((const void*)data)) ;
@ -102,7 +104,9 @@ RsItem *RsConfigSerializer::deserialise(void *data, uint32_t *size)
return NULL ; return NULL ;
} }
SerializeContext ctx(const_cast<uint8_t*>(static_cast<uint8_t*>(data)),*size,mFormat,mFlags); SerializeContext ctx(
const_cast<uint8_t*>(static_cast<uint8_t*>(data)), *size,
mFlags );
ctx.mOffset = 8 ; ctx.mOffset = 8 ;
item->serial_process(DESERIALIZE, ctx) ; item->serial_process(DESERIALIZE, ctx) ;
@ -121,50 +125,44 @@ RsItem *RsConfigSerializer::deserialise(void *data, uint32_t *size)
delete item ; delete item ;
return NULL ; return NULL ;
} }
bool RsGenericSerializer::serialise(RsItem *item,void *data,uint32_t *size)
bool RsGenericSerializer::serialise(RsItem* item, void* data, uint32_t* size)
{ {
SerializeContext ctx(static_cast<uint8_t*>(data),0,mFormat,mFlags); uint32_t tlvsize = this->size(item);
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) if(tlvsize > *size) return failure(std::errc::no_buffer_space);
throw std::runtime_error("Cannot serialise: not enough room.") ;
SerializeContext ctx(static_cast<uint8_t*>(data), tlvsize, mFlags);
if(mFlags & SERIALIZATION_FLAG_SKIP_HEADER) if(!(mFlags & RsSerializationFlags::SKIP_HEADER))
ctx.mOffset = 0;
else
{ {
if(!setRsItemHeader(data, tlvsize, item->PacketId(), tlvsize)) if(!setRsItemHeader(data, tlvsize, item->PacketId(), tlvsize))
{ return failure(std::errc::no_buffer_space);
std::cerr << "RsSerializer::serialise_item(): ERROR. Not enough size!" << std::endl;
return false ;
}
ctx.mOffset = 8; ctx.mOffset = 8;
} }
ctx.mSize = tlvsize; item->serial_process(RsGenericSerializer::SERIALIZE,ctx);
item->serial_process(RsGenericSerializer::SERIALIZE,ctx) ; if(ctx.mSize != ctx.mOffset) return failure(std::errc::message_size);
if(ctx.mSize != ctx.mOffset) *size = ctx.mOffset;
{ return true;
std::cerr << "RsSerializer::serialise(): ERROR. offset does not match expected size!" << std::endl;
return false ;
}
*size = ctx.mOffset ;
return true ;
} }
uint32_t RsGenericSerializer::size(RsItem *item) uint32_t RsGenericSerializer::size(RsItem *item)
{ {
SerializeContext ctx(NULL,0,mFormat,mFlags); SerializeContext ctx(nullptr, 0, mFlags);
if(mFlags & SERIALIZATION_FLAG_SKIP_HEADER) if(!!(mFlags & RsSerializationFlags::SKIP_HEADER)) ctx.mOffset = 0;
ctx.mOffset = 0; else ctx.mOffset = 8; // header size
else
ctx.mOffset = 8 ; // header size
item->serial_process(SIZE_ESTIMATE, ctx) ; item->serial_process(SIZE_ESTIMATE, ctx) ;
return ctx.mOffset ; return ctx.mOffset ;
@ -172,7 +170,7 @@ uint32_t RsGenericSerializer::size(RsItem *item)
void RsGenericSerializer::print(RsItem *item) void RsGenericSerializer::print(RsItem *item)
{ {
SerializeContext ctx(NULL,0,mFormat,mFlags); SerializeContext ctx(nullptr, 0, mFlags);
std::cerr << "***** RsItem class: \"" << typeid(*item).name() << "\" *****" << std::endl; std::cerr << "***** RsItem class: \"" << typeid(*item).name() << "\" *****" << std::endl;
item->serial_process(PRINT, ctx) ; item->serial_process(PRINT, ctx) ;
@ -255,7 +253,7 @@ RsItem *RsRawSerialiser::deserialise(void *data, uint32_t *pktsize)
RsGenericSerializer::SerializeContext::SerializeContext( RsGenericSerializer::SerializeContext::SerializeContext(
uint8_t* data, uint32_t size, SerializationFlags flags, uint8_t* data, uint32_t size, RsSerializationFlags flags,
RsJson::AllocatorType* allocator ) : RsJson::AllocatorType* allocator ) :
mData(data), mSize(size), mOffset(0), mOk(true), mFlags(flags), mData(data), mSize(size), mOffset(0), mOk(true), mFlags(flags),
mJson(rapidjson::kObjectType, allocator) mJson(rapidjson::kObjectType, allocator)
@ -264,20 +262,23 @@ RsGenericSerializer::SerializeContext::SerializeContext(
{ {
if(size == 0) if(size == 0)
{ {
std::cerr << __PRETTY_FUNCTION__ << " data passed without " RsFatal() << __PRETTY_FUNCTION__ << " data passed without "
<< "size! This make no sense report to developers!" << "size! This make no sense report to developers!"
<< std::endl; << std::endl;
print_stacktrace(); print_stacktrace();
exit(-EINVAL);
} }
if(flags & SERIALIZATION_FLAG_YIELDING) if(!!(flags & RsSerializationFlags::YIELDING))
{ {
std::cerr << __PRETTY_FUNCTION__ << " Attempt to create a " RsFatal() << __PRETTY_FUNCTION__
<< " Attempt to create a "
<< "binary serialization context with " << "binary serialization context with "
<< "SERIALIZATION_FLAG_YIELDING! " << "SERIALIZATION_FLAG_YIELDING! "
<< "This make no sense report to developers!" << "This make no sense report to developers!"
<< std::endl; << std::endl;
print_stacktrace(); print_stacktrace();
exit(-EINVAL);
} }
} }
} }

View File

@ -192,6 +192,39 @@ class RsRawSerialiser: public RsSerialType
virtual RsItem * deserialise(void *data, uint32_t *size); virtual RsItem * deserialise(void *data, uint32_t *size);
}; };
/** These are convenience flags to be used by the items when processing the
* data. The names of the flags are not very important. What matters is that
* the serial_process() method of each item correctly deals with the data
* when it sees the flags, if the serialiser sets them.
* By default the flags are not set and shouldn't be handled.
* When deriving a new serializer, the user can set his own flags, using
* compatible values
*/
enum class RsSerializationFlags
{
NONE = 0,
CONFIG = 1,
SIGNATURE = 2,
SKIP_HEADER = 4,
/** Used for JSON deserialization in JSON API, it causes the deserialization
* to continue even if some field is missing (or incorrect), this way the
* API is more user friendly as some methods need just part of the structs
* they take as parameters. */
YIELDING = 8,
/** When set integers typer are serialized/deserialized in Variable Length
* Quantity mode
* @see https://en.wikipedia.org/wiki/Variable-length_quantity
* This type of encoding is efficent when absoulte value is usually much
* smaller then the maximum representable with the original type.
* This encoding is also capable of representing big values at expences of a
* one more byte used.
*/
INTEGER_VLQ = 16
};
RS_REGISTER_ENUM_FLAGS_TYPE(RsSerializationFlags);
/// Top class for all services and config serializers. /// Top class for all services and config serializers.
struct RsGenericSerializer : RsSerialType struct RsGenericSerializer : RsSerialType
{ {
@ -200,63 +233,28 @@ struct RsGenericSerializer : RsSerialType
SIZE_ESTIMATE = 0x01, SIZE_ESTIMATE = 0x01,
SERIALIZE = 0x02, SERIALIZE = 0x02,
DESERIALIZE = 0x03, DESERIALIZE = 0x03,
PRINT = 0x04, PRINT = 0x04, /// @deprecated use rsdebug.h << operator instead
TO_JSON, TO_JSON,
FROM_JSON FROM_JSON
} SerializeJob; } SerializeJob;
/** @deprecated use SerializeJob instead */
RS_DEPRECATED typedef enum
{
FORMAT_BINARY = 0x01,
FORMAT_JSON = 0x02
} SerializationFormat;
struct SerializeContext struct SerializeContext
{ {
/** Allow shared allocator usage to avoid costly JSON deepcopy for /** Allow shared allocator usage to avoid costly JSON deepcopy for
* nested RsSerializable */ * nested RsSerializable */
SerializeContext( SerializeContext(
uint8_t* data = nullptr, uint32_t size = 0, uint8_t* data = nullptr, uint32_t size = 0,
SerializationFlags flags = SERIALIZATION_FLAG_NONE, RsSerializationFlags flags = RsSerializationFlags::NONE,
RsJson::AllocatorType* allocator = nullptr); RsJson::AllocatorType* allocator = nullptr);
RS_DEPRECATED SerializeContext(
uint8_t *data, uint32_t size, SerializationFormat format,
SerializationFlags flags,
RsJson::AllocatorType* allocator = nullptr) :
mData(data), mSize(size), mOffset(0), mOk(true), mFormat(format),
mFlags(flags), mJson(rapidjson::kObjectType, allocator) {}
unsigned char *mData; unsigned char *mData;
uint32_t mSize; uint32_t mSize;
uint32_t mOffset; uint32_t mOffset;
bool mOk; bool mOk;
RS_DEPRECATED SerializationFormat mFormat; RsSerializationFlags mFlags;
SerializationFlags mFlags;
RsJson mJson; RsJson mJson;
}; };
/** These are convenience flags to be used by the items when processing the
* data. The names of the flags are not very important. What matters is that
* the serial_process() method of each item correctly deals with the data
* when it sees the flags, if the serialiser sets them.
* By default the flags are not set and shouldn't be handled.
* When deriving a new serializer, the user can set his own flags, using
* compatible values
*/
static const SerializationFlags SERIALIZATION_FLAG_NONE; // 0x0000
static const SerializationFlags SERIALIZATION_FLAG_CONFIG; // 0x0001
static const SerializationFlags SERIALIZATION_FLAG_SIGNATURE; // 0x0002
static const SerializationFlags SERIALIZATION_FLAG_SKIP_HEADER; // 0x0004
/** Used for JSON deserialization in JSON API, it causes the deserialization
* to continue even if some field is missing (or incorrect), this way the
* API is more user friendly as some methods need just part of the structs
* they take as parameters. */
static const SerializationFlags SERIALIZATION_FLAG_YIELDING; // 0x0008
/** /**
* The following functions overload RsSerialType. * The following functions overload RsSerialType.
* They *should not* need to be further overloaded. * They *should not* need to be further overloaded.
@ -269,18 +267,15 @@ struct RsGenericSerializer : RsSerialType
protected: protected:
RsGenericSerializer( RsGenericSerializer(
uint8_t serial_class, uint8_t serial_type, uint8_t serial_class, uint8_t serial_type,
SerializationFormat format, SerializationFlags flags ) : RsSerializationFlags flags ):
RsSerialType( RS_PKT_VERSION1, serial_class, serial_type), RsSerialType( RS_PKT_VERSION1, serial_class, serial_type),
mFormat(format), mFlags(flags) {}
RsGenericSerializer(
uint16_t service, SerializationFormat format,
SerializationFlags flags ) :
RsSerialType( RS_PKT_VERSION_SERVICE, service ), mFormat(format),
mFlags(flags) {} mFlags(flags) {}
SerializationFormat mFormat; RsGenericSerializer(
SerializationFlags mFlags; uint16_t service, RsSerializationFlags flags ):
RsSerialType( RS_PKT_VERSION_SERVICE, service ), mFlags(flags) {}
RsSerializationFlags mFlags;
}; };
@ -290,9 +285,9 @@ protected:
struct RsServiceSerializer : RsGenericSerializer struct RsServiceSerializer : RsGenericSerializer
{ {
RsServiceSerializer( RsServiceSerializer(
uint16_t service_id, SerializationFormat format = FORMAT_BINARY, uint16_t service_id,
SerializationFlags flags = SERIALIZATION_FLAG_NONE ) : RsSerializationFlags flags = RsSerializationFlags::NONE ) :
RsGenericSerializer(service_id, format, flags) {} RsGenericSerializer(service_id, flags) {}
/*! should be overloaded to create the correct type of item depending on the /*! should be overloaded to create the correct type of item depending on the
* data */ * data */
@ -309,11 +304,10 @@ struct RsServiceSerializer : RsGenericSerializer
*/ */
struct RsConfigSerializer : RsGenericSerializer struct RsConfigSerializer : RsGenericSerializer
{ {
RsConfigSerializer(uint8_t config_class, RsConfigSerializer(
uint8_t config_type, uint8_t config_class, uint8_t config_type,
SerializationFormat format = FORMAT_BINARY, RsSerializationFlags flags = RsSerializationFlags::NONE ) :
SerializationFlags flags = SERIALIZATION_FLAG_NONE) : RsGenericSerializer(config_class, config_type, flags) {}
RsGenericSerializer(config_class,config_type,format,flags) {}
/*! should be overloaded to create the correct type of item depending on the /*! should be overloaded to create the correct type of item depending on the
* data */ * data */

View File

@ -4,7 +4,8 @@
* libretroshare: retroshare core library * * libretroshare: retroshare core library *
* * * *
* Copyright (C) 2017 Cyril Soler <csoler@users.sourceforge.net> * * Copyright (C) 2017 Cyril Soler <csoler@users.sourceforge.net> *
* Copyright (C) 2018-2019 Gioacchino Mazzurco <gio@eigenlab.org> * * Copyright (C) 2018-2020 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2020 Asociación Civil Altermundi <info@altermundi.net> *
* * * *
* This program is free software: you can redistribute it and/or modify * * This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as * * it under the terms of the GNU Lesser General Public License as *
@ -25,7 +26,7 @@
#include "serialiser/rsbaseserial.h" #include "serialiser/rsbaseserial.h"
#include "serialiser/rstlvkeys.h" #include "serialiser/rstlvkeys.h"
#include "serialiser/rsserializable.h" #include "serialiser/rsserializable.h"
#include "util/radix64.h" #include "util/rsbase64.h"
#include "util/rsprint.h" #include "util/rsprint.h"
#include "util/rstime.h" #include "util/rstime.h"
@ -34,8 +35,6 @@
#include <typeinfo> // for typeid #include <typeinfo> // for typeid
#include <rapidjson/prettywriter.h> #include <rapidjson/prettywriter.h>
static constexpr uint32_t MAX_SERIALIZED_CHUNK_SIZE = 10*1024*1024 ; // 10 MB.
#ifdef RSSERIAL_DEBUG #ifdef RSSERIAL_DEBUG
# define SAFE_GET_JSON_V() \ # define SAFE_GET_JSON_V() \
const char* mName = memberName.c_str(); \ const char* mName = memberName.c_str(); \
@ -56,32 +55,10 @@ static constexpr uint32_t MAX_SERIALIZED_CHUNK_SIZE = 10*1024*1024 ; // 10 MB.
rapidjson::Value& v = jDoc[mName] rapidjson::Value& v = jDoc[mName]
#endif // ifdef RSSERIAL_DEBUG #endif // ifdef RSSERIAL_DEBUG
//============================================================================// //============================================================================//
// std::string // // std::string //
//============================================================================// //============================================================================//
template<> uint32_t RsTypeSerializer::serial_size(const std::string& str)
{
return getRawStringSize(str);
}
template<> bool RsTypeSerializer::serialize( uint8_t data[], uint32_t size,
uint32_t& offset,
const std::string& str )
{
return setRawString(data, size, &offset, str);
}
template<> bool RsTypeSerializer::deserialize( const uint8_t data[],
uint32_t size, uint32_t &offset,
std::string& str )
{
return getRawString(data, size, &offset, str);
}
template<> void RsTypeSerializer::print_data( const std::string& n,
const std::string& str )
{
std::cerr << " [std::string] " << n << ": " << str << std::endl;
}
template<> /*static*/ template<> /*static*/
bool RsTypeSerializer::to_JSON( const std::string& membername, bool RsTypeSerializer::to_JSON( const std::string& membername,
const std::string& member, RsJson& jDoc ) const std::string& member, RsJson& jDoc )
@ -112,135 +89,11 @@ bool RsTypeSerializer::from_JSON( const std::string& memberName,
return ret; return ret;
} }
//============================================================================// //============================================================================//
// Integer types // // Integral types //
//============================================================================// //============================================================================//
template<> bool RsTypeSerializer::serialize(uint8_t data[], uint32_t size, uint32_t &offset, const bool& member)
{
return setRawUInt8(data,size,&offset,member);
}
template<> bool RsTypeSerializer::serialize(uint8_t /*data*/[], uint32_t /*size*/, uint32_t& /*offset*/, const int32_t& /*member*/)
{
std::cerr << __PRETTY_FUNCTION__ << " Not implemented!" << std::endl;
print_stacktrace();
return false;
}
template<> bool RsTypeSerializer::serialize(uint8_t data[], uint32_t size, uint32_t &offset, const uint8_t& member)
{
return setRawUInt8(data,size,&offset,member);
}
template<> bool RsTypeSerializer::serialize(uint8_t data[], uint32_t size, uint32_t &offset, const uint16_t& member)
{
return setRawUInt16(data,size,&offset,member);
}
template<> bool RsTypeSerializer::serialize(uint8_t data[], uint32_t size, uint32_t &offset, const uint32_t& member)
{
return setRawUInt32(data,size,&offset,member);
}
template<> bool RsTypeSerializer::serialize(uint8_t data[], uint32_t size, uint32_t &offset, const uint64_t& member)
{
return setRawUInt64(data,size,&offset,member);
}
template<> bool RsTypeSerializer::serialize(uint8_t data[], uint32_t size, uint32_t &offset, const rstime_t& member)
{
return setRawTimeT(data,size,&offset,member);
}
template<> bool RsTypeSerializer::deserialize(const uint8_t data[], uint32_t size, uint32_t &offset, bool& member)
{
uint8_t m;
bool ok = getRawUInt8(data,size,&offset,&m);
member = m;
return ok;
}
template<> bool RsTypeSerializer::deserialize(const uint8_t /*data*/[], uint32_t /*size*/, uint32_t& /*offset*/, int32_t& /*member*/)
{
std::cerr << __PRETTY_FUNCTION__ << " Not implemented!" << std::endl;
print_stacktrace();
return false;
}
template<> bool RsTypeSerializer::deserialize(const uint8_t data[], uint32_t size, uint32_t &offset, uint8_t& member)
{
return getRawUInt8(data,size,&offset,&member);
}
template<> bool RsTypeSerializer::deserialize(const uint8_t data[], uint32_t size, uint32_t &offset, uint16_t& member)
{
return getRawUInt16(data,size,&offset,&member);
}
template<> bool RsTypeSerializer::deserialize(const uint8_t data[], uint32_t size, uint32_t &offset, uint32_t& member)
{
return getRawUInt32(data,size,&offset,&member);
}
template<> bool RsTypeSerializer::deserialize(const uint8_t data[], uint32_t size, uint32_t &offset, uint64_t& member)
{
return getRawUInt64(data,size,&offset,&member);
}
template<> bool RsTypeSerializer::deserialize(const uint8_t data[], uint32_t size, uint32_t &offset, rstime_t& member)
{
return getRawTimeT(data,size,&offset,member);
}
template<> uint32_t RsTypeSerializer::serial_size(const bool& /* member*/)
{
return 1;
}
template<> uint32_t RsTypeSerializer::serial_size(const int32_t& /* member*/)
{
std::cerr << __PRETTY_FUNCTION__ << " Not implemented!" << std::endl;
print_stacktrace();
return 0;
}
template<> uint32_t RsTypeSerializer::serial_size(const uint8_t& /* member*/)
{
return 1;
}
template<> uint32_t RsTypeSerializer::serial_size(const uint16_t& /* member*/)
{
return 2;
}
template<> uint32_t RsTypeSerializer::serial_size(const uint32_t& /* member*/)
{
return 4;
}
template<> uint32_t RsTypeSerializer::serial_size(const uint64_t& /* member*/)
{
return 8;
}
template<> uint32_t RsTypeSerializer::serial_size(const rstime_t& /* member*/)
{
return 8;
}
template<> void RsTypeSerializer::print_data(const std::string& n, const bool & V)
{
std::cerr << " [bool ] " << n << ": " << V << std::endl;
}
template<> void RsTypeSerializer::print_data(const std::string& n, const int32_t& V)
{
std::cerr << " [int32_t ] " << n << ": " << std::to_string(V) << std::endl;
}
template<> void RsTypeSerializer::print_data(const std::string& n, const uint8_t & V)
{
std::cerr << " [uint8_t ] " << n << ": " << std::to_string(V) << std::endl;
}
template<> void RsTypeSerializer::print_data(const std::string& n, const uint16_t& V)
{
std::cerr << " [uint16_t ] " << n << ": " << std::to_string(V) << std::endl;
}
template<> void RsTypeSerializer::print_data(const std::string& n, const uint32_t& V)
{
std::cerr << " [uint32_t ] " << n << ": " << std::to_string(V) << std::endl;
}
template<> void RsTypeSerializer::print_data(const std::string& n, const uint64_t& V)
{
std::cerr << " [uint64_t ] " << n << ": " << std::to_string(V) << std::endl;
}
template<> void RsTypeSerializer::print_data(const std::string& n, const rstime_t& V)
{
std::cerr << " [rstime_t ] " << n << ": " << V << " (" << time(NULL)-V << " secs ago)" << std::endl;
}
#define SIMPLE_TO_JSON_DEF(T) \ #define SIMPLE_TO_JSON_DEF(T) \
template<> bool RsTypeSerializer::to_JSON( const std::string& memberName, \ template<> bool RsTypeSerializer::to_JSON( const std::string& memberName, \
const T& member, RsJson& jDoc ) \ const T& member, RsJson& jDoc ) \
@ -268,28 +121,45 @@ SIMPLE_TO_JSON_DEF(uint32_t)
/** Be very careful in changing this constant as it would break 64 bit integers /** Be very careful in changing this constant as it would break 64 bit integers
* members JSON string representation retrocompatibility */ * members JSON string representation retrocompatibility */
static constexpr char strReprSuffix[] = "_sixtyfour_str"; static constexpr char strReprKey[] = "xstr64";
/** While JSON doesn't have problems representing 64 bit integers JavaScript /** Be very careful in changing this constant as it would break 64 bit integers
* standard represents numbers in a double-like format thus it is not capable to * members JSON string representation retrocompatibility */
* handle safely integers outside the range [-(2^53 - 1), 2^53 - 1], so we add static constexpr char intReprKey[] = "xint64";
* to JSON also the string representation for this types as a workaround for the
* sake of JavaScript clients @see https://stackoverflow.com/a/34989371 /** While JSON doesn't have problems representing 64 bits integers JavaScript,
* Dart and other languages represents numbers in a double-like format thus they
* are not capable to handle safely integers outside the range
* [-(2^53 - 1), 2^53 - 1].
* To overcome this limitation we represent 64 bit integers as an object with
* two keys, one as integer and one as string representation.
* In our case we need to wrap those into an object instead of just adding a key
* with a suffix so support well also containers like std::map or std::vector.
* More discussion on the topic at @see https://stackoverflow.com/a/34989371
*/ */
#define SIXTYFOUR_INTEGERS_TO_JSON_DEF(T) \ #define SIXTYFOUR_INTEGERS_TO_JSON_DEF(T) \
template<> bool RsTypeSerializer::to_JSON( const std::string& memberName, \ template<> bool RsTypeSerializer::to_JSON( const std::string& memberName, \
const T& member, RsJson& jDoc ) \ const T& member, RsJson& jDoc ) \
{ \ { \
rapidjson::Document::AllocatorType& allocator = jDoc.GetAllocator(); \ using namespace rapidjson; \
Document::AllocatorType& allocator = jDoc.GetAllocator(); \
\ \
rapidjson::Value key; \ Document wrapper(rapidjson::kObjectType, &allocator); \
\
Value intKey; \
intKey.SetString(intReprKey, allocator ); \
Value intValue(member); \
wrapper.AddMember(intKey, intValue, allocator); \
\
bool ok = to_JSON(strReprKey, std::to_string(member), wrapper); \
\
Value key; \
key.SetString( memberName.c_str(), \ key.SetString( memberName.c_str(), \
static_cast<rapidjson::SizeType>(memberName.length()), \ static_cast<rapidjson::SizeType>(memberName.length()), \
allocator ); \ allocator ); \
rapidjson::Value value(member); \ jDoc.AddMember(key, wrapper, allocator); \
jDoc.AddMember(key, value, allocator); \
\ \
return to_JSON(memberName + strReprSuffix, std::to_string(member), jDoc); \ return ok; \
} }
SIXTYFOUR_INTEGERS_TO_JSON_DEF(int64_t); SIXTYFOUR_INTEGERS_TO_JSON_DEF(int64_t);
@ -345,100 +215,71 @@ bool RsTypeSerializer::from_JSON( const std::string& memberName,
return ret; return ret;
} }
/** While JSON doesn't have problems representing 64 bit integers JavaScript /** inverse of @see SIXTYFOUR_INTEGERS_TO_JSON_DEF */
* standard represents numbers in a double-like format thus it is not capable to #define SIXTYFOUR_INTEGERS_FROM_JSON_DEF(T, PRED, GET, CONV) \
* handle safely integers outside the range [-(2^53 - 1), 2^53 - 1], so we look template<> bool RsTypeSerializer::from_JSON( \
* for the string representation in the JSON for this types as a workaround for const std::string& memberName, T& member, RsJson& jDoc ) \
* the sake of JavaScript clients @see https://stackoverflow.com/a/34989371 { \
*/ using namespace rapidjson; \
template<> /*static*/ \
bool RsTypeSerializer::from_JSON( SAFE_GET_JSON_V(); \
const std::string& memberName, int64_t& member, RsJson& jDoc ) \
{ /* For retro-compatibility take it directly if it is passed as integer */ \
const char* mName = memberName.c_str(); if(v.PRED()) \
if(jDoc.HasMember(mName)) { \
{ member = v.GET(); \
rapidjson::Value& v = jDoc[mName]; return true; \
if(v.IsInt64()) } \
{ \
member = v.GetInt64(); ret = ret && v.IsObject(); \
return true; \
} if(!ret) \
} { \
Dbg3() << __PRETTY_FUNCTION__ << " " << memberName << " not found" \
Dbg4() << __PRETTY_FUNCTION__ << " int64_t " << memberName << " not found " << std::endl; \
<< "in JSON then attempt to look for string representation" return false; \
<< std::endl; } \
\
const std::string str_key = memberName + strReprSuffix; if(v.HasMember(intReprKey)) \
std::string str_value; { \
if(from_JSON(str_key, str_value, jDoc)) Value& iVal = v[intReprKey]; \
{ if(iVal.PRED()) \
try { member = std::stoll(str_value); } { \
catch (...) member = iVal.GET(); \
{ return true; \
RsErr() << __PRETTY_FUNCTION__ << " cannot convert " } \
<< str_value << " to int64_t" << std::endl; } \
return false; \
} Dbg4() << __PRETTY_FUNCTION__ << " integer representation of " << memberName \
<< " not found in JSON then attempt to look for string representation" \
return true; << std::endl; \
} \
\
Dbg3() << __PRETTY_FUNCTION__ << " neither " << memberName << " nor its " if(v.HasMember(strReprKey)) \
<< "string representation " << str_key << " has been found " { \
<< "in JSON" << std::endl; Value& sVal = v[strReprKey]; \
if(sVal.IsString()) \
return false; { \
} try { member = CONV(sVal.GetString()); } \
catch (...) \
/** While JSON doesn't have problems representing 64 bit integers JavaScript { \
* standard represents numbers in a double-like format thus it is not capable to RsErr() << __PRETTY_FUNCTION__ << " cannot convert " \
* handle safely integers outside the range [-(2^53 - 1), 2^53 - 1], so we look << sVal.GetString() << " to integral type" << std::endl; \
* for the string representation in the JSON for this types as a workaround for return false; \
* the sake of JavaScript clients @see https://stackoverflow.com/a/34989371 } \
*/ \
template<> /*static*/ return true; \
bool RsTypeSerializer::from_JSON( } \
const std::string& memberName, uint64_t& member, RsJson& jDoc ) } \
{ \
const char* mName = memberName.c_str(); Dbg3() << __PRETTY_FUNCTION__ << " neither integral representation nor " \
if(jDoc.HasMember(mName)) << "string representation found for: " << memberName << std::endl; \
{ \
rapidjson::Value& v = jDoc[mName]; return false; \
if(v.IsUint64())
{
member = v.GetUint64();
return true;
}
}
Dbg4() << __PRETTY_FUNCTION__ << " uint64_t " << memberName << " not found "
<< "in JSON then attempt to look for string representation"
<< std::endl;
const std::string str_key = memberName + strReprSuffix;
std::string str_value;
if(from_JSON(str_key, str_value, jDoc))
{
try { member = std::stoull(str_value); }
catch (...)
{
RsErr() << __PRETTY_FUNCTION__ << " cannot convert "
<< str_value << " to uint64_t" << std::endl;
return false;
}
return true;
}
Dbg3() << __PRETTY_FUNCTION__ << " neither " << memberName << " nor its "
<< "string representation " << str_key << " has been found "
<< "in JSON" << std::endl;
return false;
} }
SIXTYFOUR_INTEGERS_FROM_JSON_DEF(uint64_t, IsUint64, GetUint64, std::stoull)
SIXTYFOUR_INTEGERS_FROM_JSON_DEF( int64_t, IsInt64, GetInt64, std::stoll)
//============================================================================// //============================================================================//
// Floats // // Floats //
@ -662,113 +503,176 @@ bool RsTypeSerializer::from_JSON( const std::string& /*memberName*/,
// Binary blocks // // Binary blocks //
//============================================================================// //============================================================================//
template<> uint32_t RsTypeSerializer::serial_size(const RsTypeSerializer::TlvMemBlock_proxy& r) { return 4 + r.second ; } /*static*/ /* without this Android compilation breaks */
constexpr uint32_t RsTypeSerializer::RawMemoryWrapper::MAX_SERIALIZED_CHUNK_SIZE;
template<> bool RsTypeSerializer::deserialize(const uint8_t data[],uint32_t size,uint32_t& offset,RsTypeSerializer::TlvMemBlock_proxy& r) /*static*/
void RsTypeSerializer::RawMemoryWrapper::serial_process(
RsGenericSerializer::SerializeJob j,
RsGenericSerializer::SerializeContext& ctx )
{ {
uint32_t saved_offset = offset ; switch(j)
bool ok = deserialize<uint32_t>(data,size,offset,r.second) ;
if(r.second == 0)
{
r.first = NULL ;
if(!ok)
offset = saved_offset ;
return ok ;
}
if(r.second > MAX_SERIALIZED_CHUNK_SIZE)
{
std::cerr << "(EE) RsTypeSerializer::deserialize<TlvMemBlock_proxy>(): data chunk has size larger than safety size (" << MAX_SERIALIZED_CHUNK_SIZE << "). Item will be dropped." << std::endl;
offset = saved_offset ;
return false ;
}
r.first = (uint8_t*)rs_malloc(r.second) ;
ok = ok && (NULL != r.first);
memcpy(r.first,&data[offset],r.second) ;
offset += r.second ;
if(!ok)
offset = saved_offset ;
return ok;
}
template<> bool RsTypeSerializer::serialize(uint8_t data[],uint32_t size,uint32_t& offset,const RsTypeSerializer::TlvMemBlock_proxy& r)
{
uint32_t saved_offset = offset ;
bool ok = serialize<uint32_t>(data,size,offset,r.second) ;
memcpy(&data[offset],r.first,r.second) ;
offset += r.second ;
if(!ok)
offset = saved_offset ;
return ok;
}
template<> void RsTypeSerializer::print_data(const std::string& n, const RsTypeSerializer::TlvMemBlock_proxy& s)
{
std::cerr << " [Binary data] " << n << ", length=" << s.second << " data=" << RsUtil::BinToHex((uint8_t*)s.first,std::min(50u,s.second)) << ((s.second>50)?"...":"") << std::endl;
}
template<> /*static*/
bool RsTypeSerializer::to_JSON(
const std::string& memberName,
const RsTypeSerializer::TlvMemBlock_proxy& member, RsJson& jDoc )
{
rapidjson::Document::AllocatorType& allocator = jDoc.GetAllocator();
rapidjson::Value key;
key.SetString( memberName.c_str(),
static_cast<rapidjson::SizeType>(memberName.length()),
allocator );
std::string encodedValue;
Radix64::encode( reinterpret_cast<uint8_t*>(member.first),
static_cast<int>(member.second), encodedValue );
rapidjson::Value value;
value.SetString(encodedValue.data(), allocator);
jDoc.AddMember(key, value, allocator);
return true;
}
template<> /*static*/
bool RsTypeSerializer::from_JSON( const std::string& memberName,
RsTypeSerializer::TlvMemBlock_proxy& member,
RsJson& jDoc)
{
SAFE_GET_JSON_V();
ret = ret && v.IsString();
if(ret)
{ {
std::string encodedValue = v.GetString(); case RsGenericSerializer::SIZE_ESTIMATE:
std::vector<uint8_t> decodedValue = Radix64::decode(encodedValue); RS_SERIAL_PROCESS(second);
member.second = decodedValue.size(); ctx.mOffset += second;
break;
if(member.second == 0) case RsGenericSerializer::SERIALIZE:
if(!ctx.mOk) break;
if(second > MAX_SERIALIZED_CHUNK_SIZE)
{ {
member.first = nullptr; RsErr() << __PRETTY_FUNCTION__
return ret; << std::errc::message_size << " "
<< second << " > " << MAX_SERIALIZED_CHUNK_SIZE
<< std::endl;
print_stacktrace();
break;
}
RS_SERIAL_PROCESS(second);
if(!ctx.mOk) break;
ctx.mOk = ctx.mSize >= ctx.mOffset + second;
if(!ctx.mOk)
{
RsErr() << __PRETTY_FUNCTION__ << std::errc::no_buffer_space
<< std::endl;
print_stacktrace();
break;
}
memcpy(ctx.mData + ctx.mOffset, first, second);
ctx.mOffset += second;
break;
case RsGenericSerializer::DESERIALIZE:
{
uint32_t serialSize = 0;
RS_SERIAL_PROCESS(serialSize);
if(!ctx.mOk) break;
ctx.mOk = serialSize <= MAX_SERIALIZED_CHUNK_SIZE;
if(!ctx.mOk)
{
RsErr() << __PRETTY_FUNCTION__
<< std::errc::message_size << " "
<< serialSize << " > " << MAX_SERIALIZED_CHUNK_SIZE
<< std::endl;
clear();
break;
} }
member.first = rs_malloc(member.second); if(!serialSize)
ret = ret && member.first && {
memcpy(member.first, decodedValue.data(), member.second); Dbg3() << __PRETTY_FUNCTION__ << " Deserialized empty memory chunk"
<< std::endl;
clear();
break;
}
ctx.mOk = ctx.mSize >= ctx.mOffset + serialSize;
if(!ctx.mOk)
{
RsErr() << __PRETTY_FUNCTION__ << std::errc::no_buffer_space
<< std::endl;
print_stacktrace();
clear();
break;
}
if(serialSize != second)
{
first = reinterpret_cast<uint8_t*>(realloc(first, serialSize));
second = serialSize;
}
memcpy(first, ctx.mData + ctx.mOffset, second);
ctx.mOffset += second;
break;
}
case RsGenericSerializer::PRINT: break;
case RsGenericSerializer::TO_JSON:
{
if(!ctx.mOk) break;
std::string encodedValue;
RsBase64::encode(first, second, encodedValue, true, false);
ctx.mJson.SetString(
encodedValue.data(),
static_cast<rapidjson::SizeType>(encodedValue.length()) );
break;
}
case RsGenericSerializer::FROM_JSON:
{
const bool yelding = !!(
RsSerializationFlags::YIELDING & ctx.mFlags );
if(!(ctx.mOk || yelding))
{
clear();
break;
}
if(!ctx.mJson.IsString())
{
RsErr() << __PRETTY_FUNCTION__ << " "
<< std::errc::invalid_argument << std::endl;
print_stacktrace();
ctx.mOk = false;
clear();
break;
}
if( ctx.mJson.GetStringLength() >
RsBase64::encodedSize(MAX_SERIALIZED_CHUNK_SIZE, true) )
{
RsErr() << __PRETTY_FUNCTION__ << " "
<< std::errc::message_size << std::endl;
print_stacktrace();
ctx.mOk = false;
clear();
break;
}
std::string encodedValue = ctx.mJson.GetString();
std::vector<uint8_t> decoded;
auto ec = RsBase64::decode(encodedValue, decoded);
if(ec)
{
RsErr() << __PRETTY_FUNCTION__ << " " << ec << std::endl;
print_stacktrace();
ctx.mOk = false;
clear();
break;
}
const auto decodedSize = decoded.size();
if(!decodedSize)
{
clear();
break;
}
if(decodedSize != second)
{
first = reinterpret_cast<uint8_t*>(realloc(first, decodedSize));
second = static_cast<uint32_t>(decodedSize);
}
memcpy(first, decoded.data(), second);
break;
}
default: RsTypeSerializer::fatalUnknownSerialJob(j);
} }
return ret;
} }
void RsTypeSerializer::RawMemoryWrapper::clear()
{
free(first);
first = nullptr;
second = 0;
}
//============================================================================//
// std::error_condition //
//============================================================================//
void RsTypeSerializer::ErrConditionWrapper::serial_process( void RsTypeSerializer::ErrConditionWrapper::serial_process(
RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeJob j,
RsGenericSerializer::SerializeContext& ctx ) RsGenericSerializer::SerializeContext& ctx )
@ -778,12 +682,12 @@ void RsTypeSerializer::ErrConditionWrapper::serial_process(
case RsGenericSerializer::SIZE_ESTIMATE: // fallthrough case RsGenericSerializer::SIZE_ESTIMATE: // fallthrough
case RsGenericSerializer::DESERIALIZE: // fallthrough case RsGenericSerializer::DESERIALIZE: // fallthrough
case RsGenericSerializer::SERIALIZE: // fallthrough case RsGenericSerializer::SERIALIZE: // fallthrough
case RsGenericSerializer::FROM_JSON: case RsGenericSerializer::FROM_JSON: // [[fallthrough]]
case RsGenericSerializer::PRINT:
RsFatal() << __PRETTY_FUNCTION__ << " SerializeJob: " << j RsFatal() << __PRETTY_FUNCTION__ << " SerializeJob: " << j
<< "is not supported on std::error_condition " << std::endl; << "is not supported on std::error_condition " << std::endl;
print_stacktrace(); print_stacktrace();
exit(-2); exit(-2);
case RsGenericSerializer::PRINT: // fallthrough
case RsGenericSerializer::TO_JSON: case RsGenericSerializer::TO_JSON:
{ {
constexpr RsGenericSerializer::SerializeJob rj = constexpr RsGenericSerializer::SerializeJob rj =

File diff suppressed because it is too large Load Diff

View File

@ -80,7 +80,9 @@ p3MsgService::p3MsgService( p3ServiceControl *sc, p3IdService *id_serv,
recentlyReceivedMutex("p3MsgService recently received hash mutex"), recentlyReceivedMutex("p3MsgService recently received hash mutex"),
mGxsTransServ(gxsMS) mGxsTransServ(gxsMS)
{ {
_serialiser = new RsMsgSerialiser(RsServiceSerializer::SERIALIZATION_FLAG_NONE); // this serialiser is used for services. It's not the same than the one returned by setupSerialiser(). We need both!! /* this serialiser is used for services. It's not the same than the one
* returned by setupSerialiser(). We need both!! */
_serialiser = new RsMsgSerialiser();
addSerialType(_serialiser); addSerialType(_serialiser);
/* MsgIds are not transmitted, but only used locally as a storage index. /* MsgIds are not transmitted, but only used locally as a storage index.
@ -509,7 +511,7 @@ RsSerialiser* p3MsgService::setupSerialiser() // this serialiser is used for con
{ {
RsSerialiser *rss = new RsSerialiser ; RsSerialiser *rss = new RsSerialiser ;
rss->addSerialType(new RsMsgSerialiser(RsServiceSerializer::SERIALIZATION_FLAG_CONFIG)); rss->addSerialType(new RsMsgSerialiser(RsSerializationFlags::CONFIG));
rss->addSerialType(new RsGeneralConfigSerialiser()); rss->addSerialType(new RsGeneralConfigSerialiser());
return rss; return rss;
@ -2386,10 +2388,11 @@ void p3MsgService::sendDistantMsgItem(RsMsgItem *msgitem)
/* The item is serialized and turned into a generic turtle item. Use use the /* The item is serialized and turned into a generic turtle item. Use use the
* explicit serialiser to make sure that the msgId is not included */ * explicit serialiser to make sure that the msgId is not included */
uint32_t msg_serialized_rssize = RsMsgSerialiser(RsServiceSerializer::SERIALIZATION_FLAG_NONE).size(msgitem) ; uint32_t msg_serialized_rssize = RsMsgSerialiser().size(msgitem);
RsTemporaryMemory msg_serialized_data(msg_serialized_rssize) ; RsTemporaryMemory msg_serialized_data(msg_serialized_rssize) ;
if(!RsMsgSerialiser(RsServiceSerializer::SERIALIZATION_FLAG_NONE).serialise(msgitem,msg_serialized_data,&msg_serialized_rssize)) if( !RsMsgSerialiser().
serialise(msgitem,msg_serialized_data,&msg_serialized_rssize) )
{ {
std::cerr << "(EE) p3MsgService::sendTurtleData(): Serialization error." << std::endl; std::cerr << "(EE) p3MsgService::sendTurtleData(): Serialization error." << std::endl;
return ; return ;

View File

@ -3,7 +3,9 @@
* * * *
* libretroshare: retroshare core library * * libretroshare: retroshare core library *
* * * *
* Copyright (C) 2019 Gioacchino Mazzurco <gio@eigenlab.org> * * Copyright (C) 2019-2020 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2019-2020 Retroshare Team <contact@retroshare.cc> *
* Copyright (C) 2020 Asociación Civil Altermundi <info@altermundi.net> *
* * * *
* This program is free software: you can redistribute it and/or modify * * This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as * * it under the terms of the GNU Lesser General Public License as *
@ -27,64 +29,62 @@
/*extern*/ RsEvents* rsEvents = nullptr; /*extern*/ RsEvents* rsEvents = nullptr;
RsEvent::~RsEvent() {};
RsEvents::~RsEvents() {};
bool isEventValid( RsEvent::~RsEvent() = default;
std::shared_ptr<const RsEvent> event, std::string& errorMessage ) RsEvents::~RsEvents() = default;
/*static*/ const RsEventsErrorCategory RsEventsErrorCategory::instance;
std::error_condition RsEventsErrorCategory::default_error_condition(int ev)
const noexcept
{ {
if(!event) switch(static_cast<RsEventsErrorNum>(ev))
{ {
errorMessage = "Event is null!"; case RsEventsErrorNum::INVALID_HANDLER_ID: // [[fallthrough]];
return false; case RsEventsErrorNum::NULL_EVENT_POINTER: // [[fallthrough]];
case RsEventsErrorNum::EVENT_TYPE_UNDEFINED: // [[fallthrough]];
case RsEventsErrorNum::EVENT_TYPE_OUT_OF_RANGE:
return std::errc::invalid_argument;
default:
return std::error_condition(ev, *this);
} }
if(event->mType <= RsEventType::NONE)
{
errorMessage = "Event has type NONE: " +
std::to_string(
static_cast<std::underlying_type<RsEventType>::type >(
event->mType ) );
return false;
}
if(event->mType >= RsEventType::MAX)
{
errorMessage = "Event has type >= RsEventType::MAX: " +
std::to_string(
static_cast<std::underlying_type<RsEventType>::type >(
event->mType ) );
}
return true;
} }
bool RsEventsService::postEvent( std::shared_ptr<const RsEvent> event, std::error_condition RsEventsService::isEventTypeInvalid(RsEventType eventType)
std::string& errorMessage )
{ {
if(!isEventValid(event, errorMessage)) if(eventType == RsEventType::__NONE)
{ return RsEventsErrorNum::EVENT_TYPE_UNDEFINED;
std::cerr << __PRETTY_FUNCTION__ << " Error: "<< errorMessage
<< std::endl; if( eventType < RsEventType::__NONE ||
return false; eventType >= static_cast<RsEventType>(mHandlerMaps.size()) )
} return RsEventsErrorNum::EVENT_TYPE_OUT_OF_RANGE;
return std::error_condition();
}
std::error_condition RsEventsService::isEventInvalid(
std::shared_ptr<const RsEvent> event)
{
if(!event) return RsEventsErrorNum::NULL_EVENT_POINTER;
return isEventTypeInvalid(event->mType);
}
std::error_condition RsEventsService::postEvent(
std::shared_ptr<const RsEvent> event )
{
if(std::error_condition ec = isEventInvalid(event)) return ec;
RS_STACK_MUTEX(mEventQueueMtx); RS_STACK_MUTEX(mEventQueueMtx);
mEventQueue.push_back(event); mEventQueue.push_back(event);
return true; return std::error_condition();
} }
bool RsEventsService::sendEvent( std::shared_ptr<const RsEvent> event, std::error_condition RsEventsService::sendEvent(
std::string& errorMessage ) std::shared_ptr<const RsEvent> event )
{ {
if(!isEventValid(event, errorMessage)) if(std::error_condition ec = isEventInvalid(event)) return ec;
{
RsErr() << __PRETTY_FUNCTION__ << " "<< errorMessage << std::endl;
return false;
}
handleEvent(event); handleEvent(event);
return true; return std::error_condition();
} }
RsEventsHandlerId_t RsEventsService::generateUniqueHandlerId() RsEventsHandlerId_t RsEventsService::generateUniqueHandlerId()
@ -99,43 +99,42 @@ RsEventsHandlerId_t RsEventsService::generateUniqueHandlerId_unlocked()
return 1; return 1;
} }
bool RsEventsService::registerEventsHandler( std::error_condition RsEventsService::registerEventsHandler(
RsEventType eventType,
std::function<void(std::shared_ptr<const RsEvent>)> multiCallback, std::function<void(std::shared_ptr<const RsEvent>)> multiCallback,
RsEventsHandlerId_t& hId ) RsEventsHandlerId_t& hId, RsEventType eventType )
{ {
RS_STACK_MUTEX(mHandlerMapMtx); RS_STACK_MUTEX(mHandlerMapMtx);
if( (int)eventType > mHandlerMaps.size() + 10) if(eventType != RsEventType::__NONE)
{ if(std::error_condition ec = isEventTypeInvalid(eventType))
RsErr() << "Cannot register an event handler for an event type larger than 10 plus the max pre-defined event (value passed was " << (int)eventType << " whereas max is " << (int)RsEventType::MAX << ")" << std::endl; return ec;
return false;
}
if( (int)eventType >= mHandlerMaps.size()) if(!hId) hId = generateUniqueHandlerId_unlocked();
mHandlerMaps.resize( (int)eventType +1 ); else if (hId > mLastHandlerId)
{
print_stacktrace();
return RsEventsErrorNum::INVALID_HANDLER_ID;
}
if(!hId) mHandlerMaps[static_cast<std::size_t>(eventType)][hId] = multiCallback;
hId = generateUniqueHandlerId_unlocked(); return std::error_condition();
mHandlerMaps[(int)eventType][hId] = multiCallback;
return true;
} }
bool RsEventsService::unregisterEventsHandler(RsEventsHandlerId_t hId) std::error_condition RsEventsService::unregisterEventsHandler(
RsEventsHandlerId_t hId )
{ {
RS_STACK_MUTEX(mHandlerMapMtx); RS_STACK_MUTEX(mHandlerMapMtx);
for(uint32_t i=0;i<mHandlerMaps.size();++i) for(uint32_t i=0; i<mHandlerMaps.size(); ++i)
{ {
auto it = mHandlerMaps[i].find(hId); auto it = mHandlerMaps[i].find(hId);
if(it != mHandlerMaps[i].end()) if(it != mHandlerMaps[i].end())
{ {
mHandlerMaps[i].erase(it); mHandlerMaps[i].erase(it);
return true; return std::error_condition();
} }
} }
return false; return RsEventsErrorNum::INVALID_HANDLER_ID;
} }
void RsEventsService::threadTick() void RsEventsService::threadTick()
@ -174,27 +173,25 @@ dispatchEventFromQueueLock:
void RsEventsService::handleEvent(std::shared_ptr<const RsEvent> event) void RsEventsService::handleEvent(std::shared_ptr<const RsEvent> event)
{ {
std::function<void(std::shared_ptr<const RsEvent>)> mCallback; if(std::error_condition ec = isEventInvalid(event))
uint32_t event_type_index = static_cast<uint32_t>(event->mType);
{ {
RS_STACK_MUTEX(mHandlerMapMtx); /* LOCKED AREA */ RsErr() << __PRETTY_FUNCTION__ << " " << ec << std::endl;
print_stacktrace();
if(event_type_index >= mHandlerMaps.size() || event_type_index < 1) return;
{
RsErr() << "Cannot handle an event of type " << event_type_index << ": out of scope!" << std::endl;
return;
}
// Call all clients that registered a callback for this event type
for(auto cbit: mHandlerMaps[event_type_index])
cbit.second(event);
// Also call all clients that registered with NONE, meaning that they expect all events
for(auto cbit: mHandlerMaps[static_cast<uint32_t>(RsEventType::NONE)])
cbit.second(event);
} }
RS_STACK_MUTEX(mHandlerMapMtx);
/* It is important to also call the callback under mutex protection to
* ensure they are not unregistered in the meanwhile.
* If a callback try to fiddle with registering/unregistering it will
* deadlock */
// Call all clients that registered a callback for this event type
for(auto cbit: mHandlerMaps[static_cast<uint32_t>(event->mType)])
cbit.second(event);
/* Also call all clients that registered with NONE, meaning that they
* expect all events */
for(auto cbit: mHandlerMaps[static_cast<uint32_t>(RsEventType::__NONE)])
cbit.second(event);
} }

View File

@ -3,7 +3,8 @@
* * * *
* libretroshare: retroshare core library * * libretroshare: retroshare core library *
* * * *
* Copyright (C) 2019 Gioacchino Mazzurco <gio@eigenlab.org> * * Copyright (C) 2019-2020 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2020 Asociación Civil Altermundi <info@altermundi.net> *
* * * *
* This program is free software: you can redistribute it and/or modify * * This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as * * it under the terms of the GNU Lesser General Public License as *
@ -24,6 +25,7 @@
#include <memory> #include <memory>
#include <cstdint> #include <cstdint>
#include <deque> #include <deque>
#include <array>
#include "retroshare/rsevents.h" #include "retroshare/rsevents.h"
#include "util/rsthreads.h" #include "util/rsthreads.h"
@ -35,42 +37,44 @@ class RsEventsService :
public: public:
RsEventsService(): RsEventsService():
mHandlerMapMtx("RsEventsService::mHandlerMapMtx"), mLastHandlerId(1), mHandlerMapMtx("RsEventsService::mHandlerMapMtx"), mLastHandlerId(1),
mHandlerMaps(static_cast<int>(RsEventType::MAX)),
mEventQueueMtx("RsEventsService::mEventQueueMtx") {} mEventQueueMtx("RsEventsService::mEventQueueMtx") {}
/// @see RsEvents /// @see RsEvents
bool postEvent( std::error_condition postEvent(
std::shared_ptr<const RsEvent> event, std::shared_ptr<const RsEvent> event ) override;
std::string& errorMessage = RS_DEFAULT_STORAGE_PARAM(std::string)
) override;
/// @see RsEvents /// @see RsEvents
bool sendEvent( std::error_condition sendEvent(
std::shared_ptr<const RsEvent> event, std::shared_ptr<const RsEvent> event ) override;
std::string& errorMessage = RS_DEFAULT_STORAGE_PARAM(std::string)
) override;
/// @see RsEvents /// @see RsEvents
RsEventsHandlerId_t generateUniqueHandlerId() override; RsEventsHandlerId_t generateUniqueHandlerId() override;
/// @see RsEvents /// @see RsEvents
bool registerEventsHandler( std::error_condition registerEventsHandler(
RsEventType eventType,
std::function<void(std::shared_ptr<const RsEvent>)> multiCallback, std::function<void(std::shared_ptr<const RsEvent>)> multiCallback,
RsEventsHandlerId_t& hId = RS_DEFAULT_STORAGE_PARAM(RsEventsHandlerId_t, 0) RsEventsHandlerId_t& hId = RS_DEFAULT_STORAGE_PARAM(RsEventsHandlerId_t, 0),
) override; RsEventType eventType = RsEventType::__NONE ) override;
/// @see RsEvents /// @see RsEvents
bool unregisterEventsHandler(RsEventsHandlerId_t hId) override; std::error_condition unregisterEventsHandler(
RsEventsHandlerId_t hId ) override;
protected: protected:
std::error_condition isEventTypeInvalid(RsEventType eventType);
std::error_condition isEventInvalid(std::shared_ptr<const RsEvent> event);
RsMutex mHandlerMapMtx; RsMutex mHandlerMapMtx;
RsEventsHandlerId_t mLastHandlerId; RsEventsHandlerId_t mLastHandlerId;
std::vector< /** Storage for event handlers, keep 10 extra types for plugins that might
std::map< * be released indipendently */
RsEventsHandlerId_t, std::array<
std::function<void(std::shared_ptr<const RsEvent>)> > > mHandlerMaps; std::map<
RsEventsHandlerId_t,
std::function<void(std::shared_ptr<const RsEvent>)> >,
static_cast<std::size_t>(RsEventType::__MAX) + 10
> mHandlerMaps;
RsMutex mEventQueueMtx; RsMutex mEventQueueMtx;
std::deque< std::shared_ptr<const RsEvent> > mEventQueue; std::deque< std::shared_ptr<const RsEvent> > mEventQueue;

View File

@ -1,9 +1,9 @@
/******************************************************************************* /*******************************************************************************
* libretroshare/src/file_sharing: file_tree.h *
* * * *
* libretroshare: retroshare core library * * libretroshare < C++14 retro-compatibility helpers *
* * * *
* Copyright 2018 by Cyril Soler <csoler@users.sourceforge.net> * * Copyright (C) 2020 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2020 Asociación Civil Altermundi <info@altermundi.net> *
* * * *
* This program is free software: you can redistribute it and/or modify * * This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as * * it under the terms of the GNU Lesser General Public License as *
@ -18,37 +18,21 @@
* You should have received a copy of the GNU Lesser General Public License * * 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/>. * * along with this program. If not, see <https://www.gnu.org/licenses/>. *
* * * *
******************************************************************************/ *******************************************************************************/
#include "retroshare/rsfiles.h" #pragma once
class FileTreeImpl: public FileTree #if __cplusplus < 201402L
#include <type_traits>
namespace std
{ {
public: template<class T> using decay_t = typename decay<T>::type;
FileTreeImpl()
{
mTotalFiles = 0 ;
mTotalSize = 0 ;
}
virtual std::string toRadix64() const ; template<bool B, class T = void>
virtual bool getDirectoryContent(uint32_t index,std::string& name,std::vector<uint32_t>& subdirs,std::vector<FileData>& subfiles) const ; using enable_if_t = typename enable_if<B,T>::type;
virtual void print() const ;
bool serialise(unsigned char *& data,uint32_t& data_size) const ; template<class T>
bool deserialise(unsigned char* data, uint32_t data_size) ; using remove_const_t = typename remove_const<T>::type;
}
protected: #endif // __cplusplus < 201402L
void recurs_print(uint32_t index,const std::string& indent) const;
static void recurs_buildFileTree(FileTreeImpl& ft, uint32_t index, const DirDetails& dd, bool remote, bool remove_top_dirs);
struct DirData {
std::string name;
std::vector<uint32_t> subdirs ;
std::vector<uint32_t> subfiles ;
};
std::vector<FileData> mFiles ;
std::vector<DirData> mDirs ;
friend class FileTree ;
};

View File

@ -26,7 +26,10 @@
#include <vector> #include <vector>
#include <stdint.h> #include <stdint.h>
class Radix64 #include "util/rsdeprecate.h"
/** @deprecated use RsBase64 instead which supports also URL safe encoding */
class RS_DEPRECATED_FOR(RsBase64) Radix64
{ {
public: public:
static std::vector<uint8_t> decode(const std::string& buffer) static std::vector<uint8_t> decode(const std::string& buffer)
@ -195,5 +198,3 @@ again:
return true ; return true ;
} }
}; };

View File

@ -0,0 +1,192 @@
/*******************************************************************************
* *
* libretroshare base64 encoding utilities *
* *
* Copyright (C) 2015 Retroshare Team <contact@retroshare.cc> *
* Copyright (C) 2020 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2020 Asociación Civil Altermundi <info@altermundi.net> *
* *
* 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 <cmath>
#include "util/rsbase64.h"
#include "util/rsdebug.h"
#if __cplusplus < 201703L
/* Solve weird undefined reference error with C++ < 17 see:
* https://stackoverflow.com/questions/8016780/undefined-reference-to-static-constexpr-char
*/
/*static*/ decltype(RsBase64::bDict) constexpr RsBase64::bDict;
/*static*/ decltype(RsBase64::uDict) constexpr RsBase64::uDict;
/*static*/ decltype(RsBase64::rDict) constexpr RsBase64::rDict;
/*static*/ decltype(RsBase64::sPad) constexpr RsBase64::sPad;
#endif
/*static*/ void RsBase64::encode(
rs_view_ptr<const uint8_t> data, size_t len, std::string& outString,
bool padding, bool urlSafe )
{
const char* sDict = urlSafe ? uDict : bDict;
// Workaround if input and output are the same buffer.
bool inplace = (outString.data() == reinterpret_cast<const char*>(data));
std::string tBuff;
std::string& outStr = inplace ? tBuff : outString;
auto encSize = encodedSize(len, padding);
outStr.resize(encSize);
char* p = &outStr[0];
for (; len >= 3; len -= 3, data += 3)
{
*p++ = sDict[ (data[0] >> 2) & 077 ];
*p++ = sDict[
(((data[0] << 4) & 060) | ((data[1] >> 4) & 017)) & 077 ];
*p++ = sDict[
(((data[1] << 2) & 074) | ((data[2] >> 6) & 03)) & 077 ];
*p++ = sDict[ data[2] & 077 ];
}
if (len == 2)
{
*p++ = sDict[ (data[0] >> 2) & 077 ];
*p++ = sDict[
(((data[0] << 4) & 060) | ((data[1] >> 4) & 017)) & 077 ];
*p++ = sDict[ ((data[1] << 2) & 074) ];
if(padding) *p++ = sPad;
}
else if (len == 1)
{
*p++ = sDict[ (data[0] >> 2) & 077 ];
*p++ = sDict[ (data[0] << 4) & 060 ];
if(padding) { *p++ = sPad; *p++ = sPad; }
}
if(inplace) outString = tBuff;
}
/*static*/ std::error_condition RsBase64::decode(
const std::string& encoded, std::vector<uint8_t>& decoded )
{
size_t decSize; std::error_condition ec;
std::tie(decSize, ec) = decodedSize(encoded);
if(!decSize || ec) return ec;
size_t encSize = encoded.size();
decoded.resize(decSize);
for (size_t i = 0, o = 0; i < encSize; i += 4, o += 3)
{
char input0 = encoded[i + 0];
char input1 = encoded[i + 1];
/* At the end of the string, missing bytes 2 and 3 are considered
* padding '=' */
char input2 = i + 2 < encoded.size() ? encoded[i + 2] : sPad;
char input3 = i + 3 < encSize ? encoded[i + 3] : sPad;
// If any unknown characters appear, it's an error.
if(!( isBase64Char(input0) && isBase64Char(input1) &&
isBase64Char(input2) && isBase64Char(input3) ))
return std::errc::argument_out_of_domain;
/* If padding appears anywhere but the last 1 or 2 characters, or if
* it appears but encoded.size() % 4 != 0, it's an error. */
bool at_end = (i + 4 >= encSize);
if ( (input0 == sPad) || (input1 == sPad) ||
( input2 == sPad && !at_end ) ||
( input2 == sPad && input3 != sPad ) ||
( input3 == sPad && !at_end) )
return std::errc::illegal_byte_sequence;
uint32_t b0 = rDict[static_cast<uint8_t>(input0)] & 0x3f;
uint32_t b1 = rDict[static_cast<uint8_t>(input1)] & 0x3f;
uint32_t b2 = rDict[static_cast<uint8_t>(input2)] & 0x3f;
uint32_t b3 = rDict[static_cast<uint8_t>(input3)] & 0x3f;
uint32_t stream = (b0 << 18) | (b1 << 12) | (b2 << 6) | b3;
decoded[o + 0] = (stream >> 16) & 0xFF;
if (input2 != sPad) decoded[o + 1] = (stream >> 8) & 0xFF;
/* If there are any stale bits in this from input1, the text is
* malformed. */
else if (((stream >> 8) & 0xFF) != 0)
return std::errc::invalid_argument;
if (input3 != sPad) decoded[o + 2] = (stream >> 0) & 0xFF;
/* If there are any stale bits in this from input2, the text is
* malformed. */
else if (((stream >> 0) & 0xFF) != 0)
return std::errc::invalid_argument;
}
return std::error_condition();
}
/*static*/ size_t RsBase64::encodedSize(size_t decodedSize, bool padding)
{
if(padding) return 4 * (decodedSize + 2) / 3;
return static_cast<size_t>(
std::ceil(4L * static_cast<double>(decodedSize) / 3L) );
}
/*static*/ std::tuple<size_t, std::error_condition> RsBase64::decodedSize(
const std::string& input )
{
const auto success = [](size_t val)
{ return std::make_tuple(val, std::error_condition()); };
if(input.empty()) return success(0);
auto mod = input.size() % 4;
if(mod == 1) std::make_tuple(0, std::errc::invalid_argument);
size_t padded_size = ((input.size() + 3) / 4) * 3;
if (mod >= 2 || (mod == 0 && input[input.size() - 1] == sPad))
{
/* If the last byte is '=', or the input size % 4 is 2 or 3 (thus
* there are implied '='s), then the actual size is 1-2 bytes
* smaller. */
if ( mod == 2 || (mod == 0 && input[input.size() - 2] == sPad) )
{
/* If the second-to-last byte is also '=', or the input
* size % 4 is 2 (implying a second '='), then the actual size
* is 2 bytes smaller. */
return success(padded_size - 2);
}
else
{
/* Otherwise it's just the last character and the actual size is
* 1 byte smaller. */
return success(padded_size - 1);
}
}
return success(padded_size);
}
/*static*/ size_t RsBase64::stripInvalid(
const std::string& in, std::string& out )
{
size_t strippedCnt = 0;
auto inSize = in.size();
out.resize(inSize);
for(size_t i = 0; i < inSize; ++i)
{
if(isBase64Char(in[i])) out[i-strippedCnt] = in[i];
else ++strippedCnt;
}
out.resize(inSize-strippedCnt);
return strippedCnt;
}

View File

@ -0,0 +1,140 @@
/*******************************************************************************
* *
* libretroshare base64 encoding utilities *
* *
* Copyright (C) 2015 Retroshare Team <contact@retroshare.cc> *
* Copyright (C) 2020 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2020 Asociación Civil Altermundi <info@altermundi.net> *
* *
* 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/>. *
* *
*******************************************************************************/
#pragma once
#include <string>
#include <vector>
#include <cstdint>
#include <system_error>
#include <tuple>
#include "util/rsmemory.h"
/**
* Implement methods to encode e decode to base64 format as per RFC 4648
* This implementation support also the file name and URL safe base64url format
* @see https://tools.ietf.org/html/rfc4648#section-5
*/
class RsBase64
{
public:
/// Enable base64url by default
static constexpr bool DEFAULT_URL_SAFE = true;
/// Disable padding by default
static constexpr bool DEFAULT_PADDING = false;
/**
* @brief Encode arbitrary data to base64
* @param[in] data pointer to the input data buffer
* @param[in] len lenght of the input buffer
* @param[out] outString storage for the resulting base64 encoded string
* @param[in] padding set to true to enable padding to 32 bits
* @param[in] urlSafe pass true for base64url format, false for base64 format
*/
static void encode(
rs_view_ptr<const uint8_t> data, size_t len,
std::string& outString,
bool padding = DEFAULT_PADDING, bool urlSafe = DEFAULT_URL_SAFE );
/**
* @brief Decode data from a base64 encoded string
* @param[in] encoded encoded string
* @param[out] decoded storage for decoded data
* @return success or error details
*/
static std::error_condition decode(
const std::string& encoded, std::vector<uint8_t>& decoded );
/**
* Remove invalid characters from base64 encoded string.
* Often when copy and pasting from one progam to another long base64
* strings, new lines, spaces or other characters end up polluting the
* original text. This function is useful to cleanup the pollution before
* attempting to decode the message.
* @param in input string
* @param out storage for cleaned string. In-place operation in supported so
* the same input string may be passed.
* @return count of stripped invalid characters
*/
static size_t stripInvalid(const std::string& in, std::string& out);
/**
* Calculate how much bytes are needed to store the base64 encoded version
* of some data.
* @param decodedSize size of the original decoded data
* @param padding true to enable base64 padding
* @return how much bytes would take to store the encoded version
*/
static size_t encodedSize(
size_t decodedSize, bool padding = DEFAULT_PADDING );
/**
* @brief Calculate how much space is needed to store the decoded version of
* a base64 encoded string
* @param input encoded string
* @return decoded size, plus error information on failure
*/
static std::tuple<size_t, std::error_condition> decodedSize(
const std::string& input );
private:
/// base64 conversion table
static constexpr char bDict[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/// base64url conversion table
static constexpr char uDict[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
/// This reverse table supports both base64 and base64url
static constexpr int8_t rDict[256] = {
/* index +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 */
/* 0 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
/* 16 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
/* 32 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63,
/* 48 */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, 0, -1, -1,
/* 64 */ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
/* 80 */ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
/* 96 */ -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
/* 112 */ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
/* 128 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
/* 144 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
/* 160 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
/* 176 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
/* 192 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
/* 208 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
/* 224 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
/* 240 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
};
/// base64 padding character
static constexpr char sPad = '=';
/** Check if given character is valid either for base64 or for base64url
* @param c character to check
* @return true if valid false otherwise
*/
static inline bool isBase64Char(char c)
{ return rDict[static_cast<uint8_t>(c)] >= 0; }
};

View File

@ -46,7 +46,10 @@ struct t_RsLogger
{ {
inline t_RsLogger() = default; inline t_RsLogger() = default;
typedef t_RsLogger stream_type; /** On other platforms expose the type of underlying stream.
* On Android it cannot work like that so return the class type itself
* just for code compatibility with other platforms */
using stream_type = t_RsLogger;
template<typename T> template<typename T>
inline stream_type& operator<<(const T& val) inline stream_type& operator<<(const T& val)
@ -68,6 +71,11 @@ struct t_RsLogger
return *this; return *this;
} }
/** On other platforms return underlying stream to write avoiding additional
* prefixes. On Android it cannot work like that so return the object itself
* just for code compatibility with other platforms */
inline stream_type& uStream() { return *this; }
private: private:
std::ostringstream ostr; std::ostringstream ostr;
}; };
@ -92,7 +100,8 @@ struct t_RsLogger
{ {
inline t_RsLogger() = default; inline t_RsLogger() = default;
typedef decltype(std::cerr) stream_type; /// Expose the type of underlying stream
using stream_type = decltype(std::cerr);
template<typename T> template<typename T>
inline stream_type& operator<<(const T& val) inline stream_type& operator<<(const T& val)
@ -107,6 +116,13 @@ struct t_RsLogger
<< std::setfill('0') << std::setw(3) << msec.count() << std::setfill('0') << std::setw(3) << msec.count()
<< std::setfill(tFill) << " " << val; << std::setfill(tFill) << " " << val;
} }
/// needed for manipulators and things like std::endl
stream_type& operator<<(std::ostream& (*pf)(std::ostream&))
{ return std::cerr << pf; }
/// Return underlying stream to write avoiding additional prefixes
inline stream_type& uStream() const { return std::cerr; }
}; };
#endif // def __ANDROID__ #endif // def __ANDROID__
@ -172,16 +188,22 @@ struct RsNoDbg
{ {
inline RsNoDbg() = default; inline RsNoDbg() = default;
/** /** Defined as the type itself just for code compatibility with other
* This match most of the types, but might be not enough for templated * logging classes */
* types using stream_type = RsNoDbg;
*/
/** This match most of the types, but might be not enough for templated
* types */
template<typename T> template<typename T>
inline RsNoDbg& operator<<(const T&) { return *this; } inline stream_type& operator<<(const T&) { return *this; }
/// needed for manipulators and things like std::endl /// needed for manipulators and things like std::endl
inline RsNoDbg& operator<<(std::ostream& (*/*pf*/)(std::ostream&)) inline stream_type& operator<<(std::ostream& (*/*pf*/)(std::ostream&))
{ return *this; } { return *this; }
/** Return the object itself just for code compatibility with other
* logging classes */
inline stream_type& uStream() { return *this; }
}; };
/** /**

View File

@ -3,7 +3,9 @@
* * * *
* libretroshare: retroshare core library * * libretroshare: retroshare core library *
* * * *
* Copyright 2004-2007 by Robert Fernie <retroshare@lunamutt.com> * * Copyright (C) 2004-2007 Robert Fernie <retroshare@lunamutt.com> *
* Copyright (C) 2020 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2020 Asociación Civil Altermundi <info@altermundi.net> *
* * * *
* This program is free software: you can redistribute it and/or modify * * This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as * * it under the terms of the GNU Lesser General Public License as *
@ -265,36 +267,48 @@ bool RsDirUtil::fileExists(const std::string& filename)
bool RsDirUtil::moveFile(const std::string& source,const std::string& dest) bool RsDirUtil::moveFile(const std::string& source,const std::string& dest)
{ {
// Check that the destination directory exists. If not, create it. Dbg3() << __PRETTY_FUNCTION__<< " source: " << source
<< " dest: " << dest << std::endl;
std::string dest_dir ; std::string dest_dir ;
std::string dest_file ; std::string dest_file ;
splitDirFromFile(dest,dest_dir,dest_file) ; splitDirFromFile(dest, dest_dir, dest_file);
std::cerr << "Moving file " << source << " to " << dest << std::endl; if(!checkDirectory(dest_dir))
std::cerr << "Checking that directory " << dest_dir << " actually exists." << std::endl; {
if(!std::filesystem::create_directories(dest_dir))
{
RsErr() << __PRETTY_FUNCTION__ << " failure creating directory: "
<< dest_dir << std::endl;
return false;
}
}
if(!checkCreateDirectory(dest_dir)) // First try a rename
return false ; if(renameFile(source,dest))
{
Dbg3() << __PRETTY_FUNCTION__ << " plain rename worked" << std::endl;
return true;
}
// First try a rename /* If not, try to copy. The src and dest probably belong to different file
// * systems */
if(!copyFile(source,dest))
{
RsErr() << __PRETTY_FUNCTION__ << " failure copying file" << std::endl;
return false;
}
if(renameFile(source,dest)) // delete the original
return true ; if(!removeFile(source))
{
RsErr() << __PRETTY_FUNCTION__ << " failure deleting original file"
<< std::endl;
return false;
}
// If not, try to copy. The src and dest probably belong to different file systems return true;
if(!copyFile(source,dest))
return false ;
// copy was successful, let's delete the original
if(!removeFile(source))
return false ;
return true ;
} }
bool RsDirUtil::removeFile(const std::string& filename) bool RsDirUtil::removeFile(const std::string& filename)
@ -425,7 +439,7 @@ bool RsDirUtil::checkFile(const std::string& filename,uint64_t& file_size,bool d
} }
bool RsDirUtil::checkDirectory(const std::string& dir) bool RsDirUtil::checkDirectory(const std::string& dir)
{ {
int val; int val;
mode_t st_mode; mode_t st_mode;
@ -461,11 +475,9 @@ bool RsDirUtil::checkDirectory(const std::string& dir)
} }
bool RsDirUtil::checkCreateDirectory(const std::string& dir) bool RsDirUtil::checkCreateDirectory(const std::string& dir)
{ {
#ifdef RSDIR_DEBUG Dbg3() << __PRETTY_FUNCTION__ << " " << dir << std::endl;
std::cerr << "RsDirUtil::checkCreateDirectory() dir: " << dir << std::endl;
#endif
#ifdef WINDOWS_SYS #ifdef WINDOWS_SYS
std::wstring wdir; std::wstring wdir;
@ -516,6 +528,23 @@ bool RsDirUtil::checkCreateDirectory(const std::string& dir)
return true; return true;
} }
#if __cplusplus < 201703L
bool std::filesystem::create_directories(const std::string& path)
{
for( std::string::size_type lastIndex = 0; lastIndex < std::string::npos;
lastIndex = path.find('/', lastIndex) )
{
std::string&& curDir = path.substr(0, ++lastIndex);
if(!RsDirUtil::checkCreateDirectory(curDir))
{
RsErr() << __PRETTY_FUNCTION__ << " failure creating: " << curDir
<< " of: " << path << std::endl;
return false;
}
}
return true;
}
#endif // __cplusplus < 201703L
std::string RsDirUtil::removeSymLinks(const std::string& path) std::string RsDirUtil::removeSymLinks(const std::string& path)
{ {

View File

@ -3,7 +3,9 @@
* * * *
* libretroshare: retroshare core library * * libretroshare: retroshare core library *
* * * *
* Copyright 2004-2007 by Robert Fernie <retroshare@lunamutt.com> * * Copyright (C) 2004-2007 Robert Fernie <retroshare@lunamutt.com> *
* Copyright (C) 2020 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2020 Asociación Civil Altermundi <info@altermundi.net> *
* * * *
* This program is free software: you can redistribute it and/or modify * * This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as * * it under the terms of the GNU Lesser General Public License as *
@ -20,8 +22,7 @@
* * * *
*******************************************************************************/ *******************************************************************************/
#ifndef RSUTIL_DIRFNS_H #pragma once
#define RSUTIL_DIRFNS_H
#include <string> #include <string>
#include <list> #include <list>
@ -84,7 +85,10 @@ int breakupDirList(const std::string& path, std::list<std::string> &subdirs
bool splitDirFromFile(const std::string& full_path,std::string& dir, std::string& file); bool splitDirFromFile(const std::string& full_path,std::string& dir, std::string& file);
bool copyFile(const std::string& source,const std::string& dest); bool copyFile(const std::string& source,const std::string& dest);
bool moveFile(const std::string& source,const std::string& dest);
/** Move file. If destination directory doesn't exists create it. */
bool moveFile(const std::string& source, const std::string& dest);
bool removeFile(const std::string& file); bool removeFile(const std::string& file);
bool fileExists(const std::string& file); bool fileExists(const std::string& file);
bool checkFile(const std::string& filename,uint64_t& file_size,bool disallow_empty_file = false); bool checkFile(const std::string& filename,uint64_t& file_size,bool disallow_empty_file = false);
@ -141,8 +145,20 @@ bool getWideFileHash(std::wstring filepath, RsFileHash &hash, u
FILE *rs_fopen(const char* filename, const char* mode); FILE *rs_fopen(const char* filename, const char* mode);
std::string convertPathToUnix(std::string path); std::string convertPathToUnix(std::string path);
/** Concatenate two path pieces putting '/' separator between them only if
* needed */
std::string makePath(const std::string &path1, const std::string &path2); std::string makePath(const std::string &path1, const std::string &path2);
RS_SET_CONTEXT_DEBUG_LEVEL(1);
} }
#if __cplusplus < 201703L
#endif namespace std
{
namespace filesystem
{
bool create_directories(const std::string& path);
}
}
#endif // __cplusplus < 201703L

View File

@ -0,0 +1,59 @@
/*******************************************************************************
* *
* libretroshare base64 encoding utilities *
* *
* Copyright (C) 2020 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2020 Asociación Civil Altermundi <info@altermundi.net> *
* *
* 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/>. *
* *
*******************************************************************************/
#pragma once
/**
* @file
* This file provide convenient integer endiannes conversion utilities.
* Instead of providing them with different names for each type (a la C htonl,
* htons, ntohl, ntohs ), which make them uncomfortable to use, expose a
* templated function `rs_endian_fix` to reorder integers representation byets
* when sending or receiving from the network. */
/* enforce LITTLE_ENDIAN on Windows */
#ifdef WINDOWS_SYS
# define BYTE_ORDER 1234
# define LITTLE_ENDIAN 1234
# define BIG_ENDIAN 4321
#else
#include <arpa/inet.h>
#endif
template<typename INTTYPE> inline INTTYPE rs_endian_fix(INTTYPE val)
{
#if BYTE_ORDER == LITTLE_ENDIAN
INTTYPE swapped = 0;
for (size_t i = 0; i < sizeof(INTTYPE); ++i)
swapped |= (val >> (8*(sizeof(INTTYPE)-i-1)) & 0xFF) << (8*i);
return swapped;
#else
return hostI;
#endif
};
#ifndef BYTE_ORDER
# error "ENDIAN determination Failed (BYTE_ORDER not defined)"
#endif
#if !(BYTE_ORDER == BIG_ENDIAN || BYTE_ORDER == LITTLE_ENDIAN)
# error "ENDIAN determination Failed (unkown BYTE_ORDER value)"
#endif

View File

@ -4,7 +4,7 @@
* libretroshare: retroshare core library * * libretroshare: retroshare core library *
* * * *
* Copyright 2012 Cyril Soler <csoler@users.sourceforge.net> * * Copyright 2012 Cyril Soler <csoler@users.sourceforge.net> *
* Copyright 2019 Gioacchino Mazzurco <gio@altermundi.net> * * Copyright 2019-2020 Gioacchino Mazzurco <gio@altermundi.net> *
* * * *
* This program is free software: you can redistribute it and/or modify * * This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as * * it under the terms of the GNU Lesser General Public License as *
@ -62,7 +62,6 @@ bool myFunnyFunction(
*/ */
#define RS_DEFAULT_STORAGE_PARAM(Type,...) *std::unique_ptr<Type>(new Type(__VA_ARGS__)) #define RS_DEFAULT_STORAGE_PARAM(Type,...) *std::unique_ptr<Type>(new Type(__VA_ARGS__))
/** @brief Safely dynamic cast between std::unique_ptr of different types /** @brief Safely dynamic cast between std::unique_ptr of different types
* std::unique_ptr semantic rely on the invariant that only one instance own * std::unique_ptr semantic rely on the invariant that only one instance own
* the object, when casting between differents types one would be tempted to do * the object, when casting between differents types one would be tempted to do
@ -90,9 +89,28 @@ bool rs_unique_cast(
return false; return false;
} }
/** Mark a pointer as non-owned aka it must not be deleted/freed in that context.
* If a function take an `rs_view_ptr` as paramether it means that she will not
* own (aka free/delete) the passed memory, instead the caller is in charge of
* managing it. If a function return an `rs_view_ptr` it means the memory is
* managed internally and the caller should not call free/delete on it.
* @see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1408r0.pdf */
template<typename T> using rs_view_ptr = T*;
/** Mark a pointer as owned aka the receiving context is in charge of dealing
* with it by free/delete once finished.
* If a function take an `rs_owner_ptr` as paramether it means that she will own
* (aka free/delete when finished using it) the passed memory, instead the
* caller is NOT in charge of managing it.
* If a function return an `rs_owner_ptr` it means the memory is NOT managed
* internally and the caller should call free/delete on it once finished using
* it.
* @see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1408r0.pdf */
template<typename T> using rs_owner_ptr = T*;
void *rs_malloc(size_t size) ; void *rs_malloc(size_t size) ;
/** @deprecated use std::unique_ptr instead
// This is a scope guard to release the memory block when going of of the current scope. // This is a scope guard to release the memory block when going of of the current scope.
// Can be very useful to auto-delete some memory on quit without the need to call free each time. // Can be very useful to auto-delete some memory on quit without the need to call free each time.
// //
@ -109,11 +127,11 @@ void *rs_malloc(size_t size) ;
// [do something] // [do something]
// //
// } // mem gets freed automatically // } // mem gets freed automatically
// */
class RsTemporaryMemory class RsTemporaryMemory
{ {
public: public:
RsTemporaryMemory(size_t s) explicit RsTemporaryMemory(size_t s)
{ {
_mem = (unsigned char *)rs_malloc(s) ; _mem = (unsigned char *)rs_malloc(s) ;
@ -127,14 +145,7 @@ public:
size_t size() const { return _size ; } size_t size() const { return _size ; }
~RsTemporaryMemory() ~RsTemporaryMemory() { free(_mem); }
{
if(_mem != NULL)
{
free(_mem) ;
_mem = NULL ;
}
}
private: private:
unsigned char *_mem ; unsigned char *_mem ;

View File

@ -224,7 +224,7 @@ RsUrl& RsUrl::delQueryK(const std::string& key)
} }
bool RsUrl::hasQueryK(const std::string& key) bool RsUrl::hasQueryK(const std::string& key)
{ return (mQuery.find(key) != mQuery.end()); } { return (mQuery.find(key) != mQuery.end()); }
const std::string* RsUrl::getQueryV(const std::string& key) rs_view_ptr<const std::string> RsUrl::getQueryV(const std::string& key)
{ {
if(hasQueryK(key)) return &(mQuery.find(key)->second); if(hasQueryK(key)) return &(mQuery.find(key)->second);
return nullptr; return nullptr;

View File

@ -20,6 +20,7 @@
#include <string> #include <string>
#include <map> #include <map>
#include "util/rsmemory.h"
#include "serialiser/rsserializable.h" #include "serialiser/rsserializable.h"
struct sockaddr_storage; struct sockaddr_storage;
@ -63,7 +64,7 @@ struct RsUrl : RsSerializable
RsUrl& setQueryKV(const std::string& key, const std::string& value); RsUrl& setQueryKV(const std::string& key, const std::string& value);
RsUrl& delQueryK(const std::string& key); RsUrl& delQueryK(const std::string& key);
bool hasQueryK(const std::string& key); bool hasQueryK(const std::string& key);
const std::string* getQueryV(const std::string& key); rs_view_ptr<const std::string> getQueryV(const std::string& key);
const std::string& fragment() const; const std::string& fragment() const;
RsUrl& setFragment(const std::string& fragment); RsUrl& setFragment(const std::string& fragment);

View File

@ -462,9 +462,9 @@ char *ops_get_passphrase(void)
{ {
#ifndef __ANDROID__ #ifndef __ANDROID__
return ops_malloc_passphrase(getpass("Passphrase: ")); return ops_malloc_passphrase(getpass("Passphrase: "));
#else // __ANDROID__ #else // __ANDROID
return ops_malloc_passphrase("getpass not supported on android"); // We should never get here on Android, getpass not supported.
#warning "getpass not supported on android" abort();
#endif // __ANDROID__ #endif // __ANDROID__
} }

View File

@ -623,10 +623,7 @@ void SharedFilesDialog::copyLinks(const QModelIndexList& lst, bool remote,QList<
if (details.type == DIR_TYPE_DIR) if (details.type == DIR_TYPE_DIR)
{ {
FileTree *ft = FileTree::create(details,remote) ; auto ft = RsFileTree::fromDirDetails(details,remote);
std::cerr << "Created collection file tree:" << std::endl;
ft->print();
QString dir_name = QDir(QString::fromUtf8(details.name.c_str())).dirName(); QString dir_name = QDir(QString::fromUtf8(details.name.c_str())).dirName();
@ -634,8 +631,6 @@ void SharedFilesDialog::copyLinks(const QModelIndexList& lst, bool remote,QList<
if(link.valid()) if(link.valid())
urls.push_back(link) ; urls.push_back(link) ;
delete ft ;
} }
else else
{ {

View File

@ -1076,30 +1076,36 @@ TransfersDialog::TransfersDialog(QWidget *parent)
// load settings // load settings
processSettings(true); processSettings(true);
int S = QFontMetricsF(font()).height(); int S = static_cast<int>(QFontMetricsF(font()).height());
QString help_str = tr( QString help_str = tr(
" <h1><img width=\"%1\" src=\":/icons/help_64.png\">&nbsp;&nbsp;File Transfer</h1> \ "<h1><img width=\"%1\" src=\":/icons/help_64.png\">&nbsp;&nbsp;"
<p>Retroshare brings two ways of transferring files: direct transfers from your friends, and \ "File Transfer</h1>"
distant anonymous tunnelled transfers. In addition, file transfer is multi-source and allows swarming \ "<p>Retroshare brings two ways of transferring files: direct "
(you can be a source while downloading)</p> \ "transfers from your friends, and distant anonymous tunnelled "
<p>You can share files using the <img src=\":/images/directoryadd_24x24_shadow.png\" width=%2 /> icon from the left side bar. \ "transfers. In addition, file transfer is multi-source and "
These files will be listed in the My Files tab. You can decide for each friend group whether they can or not see these files \ "allows swarming (you can be a source while downloading)</p>"
in their Friends Files tab</p>\ "<p>You can share files using the "
<p>The search tab reports files from your friends' file lists, and distant files that can be reached \ "<img src=\":/images/directoryadd_24x24_shadow.png\" width=%2 />"
anonymously using the multi-hop tunnelling system.</p> \ " icon from the left side bar. These files will be listed in "
").arg(QString::number(2*S)).arg(QString::number(S)) ; "the My Files tab. You can decide for each friend group whether"
" they can or not see these files in their Friends Files tab</p>"
"<p>The search tab reports files from your friends' file lists,"
" and distant files that can be reached anonymously using the "
"multi-hop tunnelling system.</p>")
.arg(QString::number(2*S)).arg(QString::number(S)) ;
registerHelpButton(ui.helpButton,help_str,"TransfersDialog") ; registerHelpButton(ui.helpButton,help_str,"TransfersDialog") ;
mEventHandlerId=0; mEventHandlerId=0;
rsEvents->registerEventsHandler(RsEventType::FILE_TRANSFER, [this](std::shared_ptr<const RsEvent> event) { handleEvent(event); }, mEventHandlerId ); rsEvents->registerEventsHandler(
[this](std::shared_ptr<const RsEvent> event) { handleEvent(event); },
mEventHandlerId, RsEventType::FILE_TRANSFER );
} }
void TransfersDialog::handleEvent(std::shared_ptr<const RsEvent> event) void TransfersDialog::handleEvent(std::shared_ptr<const RsEvent> event)
{ {
if(event->mType != RsEventType::FILE_TRANSFER) if(event->mType != RsEventType::FILE_TRANSFER) return;
return;
const RsFileTransferEvent *fe = dynamic_cast<const RsFileTransferEvent*>(event.get()); const RsFileTransferEvent *fe = dynamic_cast<const RsFileTransferEvent*>(event.get());
if(!fe) if(!fe)
@ -2225,9 +2231,8 @@ void TransfersDialog::pasteLink()
for(QList<RetroShareLink>::const_iterator it(links.begin());it!=links.end();++it) for(QList<RetroShareLink>::const_iterator it(links.begin());it!=links.end();++it)
{ {
FileTree *ft = FileTree::create((*it).radix().toStdString()) ; auto ft = RsFileTree::fromRadix64((*it).radix().toStdString());
col.merge_in(*ft);
col.merge_in(*ft) ;
} }
links.clear(); links.clear();
RSLinkClipboard::pasteLinks(links,RetroShareLink::TYPE_FILE); RSLinkClipboard::pasteLinks(links,RetroShareLink::TYPE_FILE);

View File

@ -149,11 +149,17 @@ IdDialog::IdDialog(QWidget *parent) : MainPage(parent), ui(new Ui::IdDialog)
{ {
ui->setupUi(this); ui->setupUi(this);
mEventHandlerId_identity = 0; mEventHandlerId_identity = 0;
rsEvents->registerEventsHandler(RsEventType::GXS_IDENTITY, [this](std::shared_ptr<const RsEvent> event) { RsQThreadUtils::postToObject( [=]() { handleEvent_main_thread(event); }, this ); }, mEventHandlerId_identity ); rsEvents->registerEventsHandler(
[this](std::shared_ptr<const RsEvent> event)
{ RsQThreadUtils::postToObject([=](){ handleEvent_main_thread(event); }, this); },
mEventHandlerId_identity, RsEventType::GXS_IDENTITY );
mEventHandlerId_circles = 0; mEventHandlerId_circles = 0;
rsEvents->registerEventsHandler(RsEventType::GXS_CIRCLES, [this](std::shared_ptr<const RsEvent> event) { RsQThreadUtils::postToObject( [=]() { handleEvent_main_thread(event); }, this ); }, mEventHandlerId_circles ); rsEvents->registerEventsHandler(
[this](std::shared_ptr<const RsEvent> event)
{ RsQThreadUtils::postToObject([=](){ handleEvent_main_thread(event); }, this); },
mEventHandlerId_circles, RsEventType::GXS_CIRCLES );
// This is used to grab the broadcast of changes from p3GxsCircles, which is discarded by the current dialog, since it expects data for p3Identity only. // This is used to grab the broadcast of changes from p3GxsCircles, which is discarded by the current dialog, since it expects data for p3Identity only.
//mCirclesBroadcastBase = new RsGxsUpdateBroadcastBase(rsGxsCircles, this); //mCirclesBroadcastBase = new RsGxsUpdateBroadcastBase(rsGxsCircles, this);

View File

@ -67,12 +67,11 @@
* #define NEWS_DEBUG 1 * #define NEWS_DEBUG 1
****/ ****/
static NewsFeed *instance = NULL; static NewsFeed* instance = nullptr;
/** Constructor */ /** Constructor */
NewsFeed::NewsFeed(QWidget *parent) : MainPage(parent), ui(new Ui::NewsFeed) NewsFeed::NewsFeed(QWidget *parent) : MainPage(parent), ui(new Ui::NewsFeed),
{ mEventTypes({
mEventTypes = {
RsEventType::AUTHSSL_CONNECTION_AUTENTICATION, RsEventType::AUTHSSL_CONNECTION_AUTENTICATION,
RsEventType::PEER_CONNECTION , RsEventType::PEER_CONNECTION ,
RsEventType::GXS_CIRCLES , RsEventType::GXS_CIRCLES ,
@ -80,12 +79,14 @@ NewsFeed::NewsFeed(QWidget *parent) : MainPage(parent), ui(new Ui::NewsFeed)
RsEventType::GXS_FORUMS , RsEventType::GXS_FORUMS ,
RsEventType::GXS_POSTED , RsEventType::GXS_POSTED ,
RsEventType::MAIL_STATUS RsEventType::MAIL_STATUS
}; })
{
for(uint32_t i=0;i<mEventTypes.size();++i) for(uint32_t i=0;i<mEventTypes.size();++i)
{ {
mEventHandlerIds.push_back(0); // needed to force intialization by registerEventsHandler() mEventHandlerIds.push_back(0); // needed to force intialization by registerEventsHandler()
rsEvents->registerEventsHandler(mEventTypes[i], [this](std::shared_ptr<const RsEvent> event) { handleEvent(event); }, mEventHandlerIds.back() ); rsEvents->registerEventsHandler(
[this](std::shared_ptr<const RsEvent> event) { handleEvent(event); },
mEventHandlerIds.back(), mEventTypes[i] );
} }
/* Invoke the Qt Designer generated object setup routine */ /* Invoke the Qt Designer generated object setup routine */

View File

@ -41,13 +41,14 @@ public:
}; };
/** Constructor */ /** Constructor */
PostedDialog::PostedDialog(QWidget *parent) PostedDialog::PostedDialog(QWidget *parent):
: GxsGroupFrameDialog(rsPosted, parent) GxsGroupFrameDialog(rsPosted, parent), mEventHandlerId(0)
{ {
mEventHandlerId = 0; // Needs to be asynced because this function is likely to be called by another thread!
// Needs to be asynced because this function is likely to be called by another thread! rsEvents->registerEventsHandler(
[this](std::shared_ptr<const RsEvent> event)
rsEvents->registerEventsHandler(RsEventType::GXS_POSTED, [this](std::shared_ptr<const RsEvent> event) { RsQThreadUtils::postToObject( [=]() { handleEvent_main_thread(event); }, this ); }, mEventHandlerId ); { RsQThreadUtils::postToObject( [=]() { handleEvent_main_thread(event); }, this ); },
mEventHandlerId, RsEventType::GXS_POSTED );
} }
void PostedDialog::handleEvent_main_thread(std::shared_ptr<const RsEvent> event) void PostedDialog::handleEvent_main_thread(std::shared_ptr<const RsEvent> event)

View File

@ -107,9 +107,11 @@ PostedListWidget::PostedListWidget(const RsGxsGroupId &postedId, QWidget *parent
processSettings(true); processSettings(true);
mEventHandlerId = 0; mEventHandlerId = 0;
// Needs to be asynced because this function is likely to be called by another thread! // Needs to be asynced because this function is called by another thread!
rsEvents->registerEventsHandler(
rsEvents->registerEventsHandler(RsEventType::GXS_POSTED, [this](std::shared_ptr<const RsEvent> event) { RsQThreadUtils::postToObject( [=]() { handleEvent_main_thread(event); }, this ); }, mEventHandlerId ); [this](std::shared_ptr<const RsEvent> event)
{ RsQThreadUtils::postToObject( [=]() { handleEvent_main_thread(event); }, this ); },
mEventHandlerId, RsEventType::GXS_POSTED );
/* Initialize GUI */ /* Initialize GUI */
setGroupId(postedId); setGroupId(postedId);

View File

@ -1706,15 +1706,13 @@ static void processList(const QStringList &list, const QString &textSingular, co
} }
break; break;
case TYPE_FILE_TREE: case TYPE_FILE_TREE:
{ {
FileTree *ft = FileTree::create(link.radix().toStdString()) ; auto ft = RsFileTree::fromRadix64(
link.radix().toStdString() );
RsCollection(*ft).downloadFiles() ; RsCollection(*ft).downloadFiles();
delete ft;
}
break; break;
}
case TYPE_CHAT_ROOM: case TYPE_CHAT_ROOM:
{ {

View File

@ -177,8 +177,10 @@ NewFriendList::NewFriendList(QWidget *parent) : /* RsAutoUpdatePage(5000,parent)
ui->filterLineEdit->setPlaceholderText(tr("Search")) ; ui->filterLineEdit->setPlaceholderText(tr("Search")) ;
ui->filterLineEdit->showFilterIcon(); ui->filterLineEdit->showFilterIcon();
mEventHandlerId=0; // forces initialization mEventHandlerId=0; // forces initialization
rsEvents->registerEventsHandler( RsEventType::PEER_CONNECTION, [this](std::shared_ptr<const RsEvent> e) { handleEvent(e); }, mEventHandlerId ); rsEvents->registerEventsHandler(
[this](std::shared_ptr<const RsEvent> e) { handleEvent(e); },
mEventHandlerId, RsEventType::PEER_CONNECTION );
mModel = new RsFriendListModel(); mModel = new RsFriendListModel();
mProxyModel = new FriendListSortFilterProxyModel(ui->peerTreeWidget->header(),this); mProxyModel = new FriendListSortFilterProxyModel(ui->peerTreeWidget->header(),this);

View File

@ -44,7 +44,7 @@ RsCollection::RsCollection(QObject *parent)
_xml_doc.appendChild(_root); _xml_doc.appendChild(_root);
} }
RsCollection::RsCollection(const FileTree& fr) RsCollection::RsCollection(const RsFileTree& fr)
: _xml_doc("RsCollection") : _xml_doc("RsCollection")
{ {
_root = _xml_doc.createElement("RsCollection"); _root = _xml_doc.createElement("RsCollection");
@ -153,7 +153,7 @@ void RsCollection::merge_in(const QString& fname,uint64_t size,const RsFileHash&
recursAddElements(_xml_doc,info,_root) ; recursAddElements(_xml_doc,info,_root) ;
} }
void RsCollection::merge_in(const FileTree& tree) void RsCollection::merge_in(const RsFileTree& tree)
{ {
recursAddElements(_xml_doc,tree,0,_root) ; recursAddElements(_xml_doc,tree,0,_root) ;
} }
@ -273,14 +273,14 @@ void RsCollection::recursAddElements(QDomDocument& doc,const ColFileInfo& colFil
} }
} }
void RsCollection::recursAddElements(QDomDocument& doc,const FileTree& ft,uint32_t index,QDomElement& e) const void RsCollection::recursAddElements(
QDomDocument& doc, const RsFileTree& ft, uint32_t index,
QDomElement& e ) const
{ {
std::vector<uint32_t> subdirs ; std::vector<uint64_t> subdirs;
std::vector<FileTree::FileData> subfiles ; std::vector<RsFileTree::FileData> subfiles ;
std::string name; std::string name;
if(!ft.getDirectoryContent(name, subdirs, subfiles, index)) return;
if(!ft.getDirectoryContent(index,name,subdirs,subfiles))
return ;
QDomElement d = doc.createElement("Directory") ; QDomElement d = doc.createElement("Directory") ;
d.setAttribute(QString("name"),QString::fromUtf8(name.c_str())) ; d.setAttribute(QString("name"),QString::fromUtf8(name.c_str())) ;

View File

@ -62,11 +62,11 @@ public:
RsCollection(QObject *parent = 0) ; RsCollection(QObject *parent = 0) ;
// create from list of files and directories // create from list of files and directories
RsCollection(const std::vector<DirDetails>& file_entries, FileSearchFlags flags, QObject *parent = 0) ; RsCollection(const std::vector<DirDetails>& file_entries, FileSearchFlags flags, QObject *parent = 0) ;
RsCollection(const FileTree& fr); RsCollection(const RsFileTree& fr);
virtual ~RsCollection() ; virtual ~RsCollection() ;
void merge_in(const QString& fname,uint64_t size,const RsFileHash& hash) ; void merge_in(const QString& fname,uint64_t size,const RsFileHash& hash) ;
void merge_in(const FileTree& tree) ; void merge_in(const RsFileTree& tree) ;
static const QString ExtensionString ; static const QString ExtensionString ;
@ -99,7 +99,9 @@ private:
void recursAddElements(QDomDocument&, const DirDetails&, QDomElement&, FileSearchFlags flags) const ; void recursAddElements(QDomDocument&, const DirDetails&, QDomElement&, FileSearchFlags flags) const ;
void recursAddElements(QDomDocument&,const ColFileInfo&,QDomElement&) const; void recursAddElements(QDomDocument&,const ColFileInfo&,QDomElement&) const;
void recursAddElements(QDomDocument& doc,const FileTree& ft,uint32_t index,QDomElement& e) const; void recursAddElements(
QDomDocument& doc, const RsFileTree& ft, uint32_t index,
QDomElement& e ) const;
void recursCollectColFileInfos(const QDomElement&,std::vector<ColFileInfo>& colFileInfos,const QString& current_dir,bool bad_chars_in_parent) const ; void recursCollectColFileInfos(const QDomElement&,std::vector<ColFileInfo>& colFileInfos,const QString& current_dir,bool bad_chars_in_parent) const ;
// check that the file is a valid rscollection file, and not a lol bomb or some shit like this // check that the file is a valid rscollection file, and not a lol bomb or some shit like this

View File

@ -47,12 +47,14 @@
// }; // };
/** Constructor */ /** Constructor */
GxsChannelDialog::GxsChannelDialog(QWidget *parent) GxsChannelDialog::GxsChannelDialog(QWidget *parent):
: GxsGroupFrameDialog(rsGxsChannels, parent,true) GxsGroupFrameDialog(rsGxsChannels, parent, true), mEventHandlerId(0)
{ {
mEventHandlerId = 0; // Needs to be asynced because this function is called by another thread!
// Needs to be asynced because this function is likely to be called by another thread! rsEvents->registerEventsHandler(
rsEvents->registerEventsHandler(RsEventType::GXS_CHANNELS, [this](std::shared_ptr<const RsEvent> event) { RsQThreadUtils::postToObject( [=]() { handleEvent_main_thread(event); }, this ); }, mEventHandlerId ); [this](std::shared_ptr<const RsEvent> event)
{ RsQThreadUtils::postToObject([=]() { handleEvent_main_thread(event); }, this ); },
mEventHandlerId, RsEventType::GXS_CHANNELS );
} }
void GxsChannelDialog::handleEvent_main_thread(std::shared_ptr<const RsEvent> event) void GxsChannelDialog::handleEvent_main_thread(std::shared_ptr<const RsEvent> event)

View File

@ -130,9 +130,11 @@ GxsChannelPostsWidget::GxsChannelPostsWidget(const RsGxsGroupId &channelId, QWid
setGroupId(channelId); setGroupId(channelId);
mEventHandlerId = 0; mEventHandlerId = 0;
// Needs to be asynced because this function is likely to be called by another thread! // Needs to be asynced because this function is called by another thread!
rsEvents->registerEventsHandler(
rsEvents->registerEventsHandler(RsEventType::GXS_CHANNELS, [this](std::shared_ptr<const RsEvent> event) { RsQThreadUtils::postToObject( [=]() { handleEvent_main_thread(event); }, this ); }, mEventHandlerId ); [this](std::shared_ptr<const RsEvent> event)
{ RsQThreadUtils::postToObject([=](){ handleEvent_main_thread(event); }, this ); },
mEventHandlerId, RsEventType::GXS_CHANNELS );
} }
void GxsChannelPostsWidget::handleEvent_main_thread(std::shared_ptr<const RsEvent> event) void GxsChannelPostsWidget::handleEvent_main_thread(std::shared_ptr<const RsEvent> event)

View File

@ -345,10 +345,12 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget
ui->threadTreeWidget->enableColumnCustomize(true); ui->threadTreeWidget->enableColumnCustomize(true);
#endif #endif
mEventHandlerId = 0; mEventHandlerId = 0;
// Needs to be asynced because this function is likely to be called by another thread! // Needs to be asynced because this function is called by another thread!
rsEvents->registerEventsHandler(
rsEvents->registerEventsHandler(RsEventType::GXS_FORUMS, [this](std::shared_ptr<const RsEvent> event) { RsQThreadUtils::postToObject( [=]() { handleEvent_main_thread(event); }, this ); }, mEventHandlerId ); [this](std::shared_ptr<const RsEvent> event)
{ RsQThreadUtils::postToObject([=](){ handleEvent_main_thread(event); }, this ); },
mEventHandlerId, RsEventType::GXS_FORUMS );
} }
void GxsForumThreadWidget::handleEvent_main_thread(std::shared_ptr<const RsEvent> event) void GxsForumThreadWidget::handleEvent_main_thread(std::shared_ptr<const RsEvent> event)

View File

@ -38,14 +38,15 @@ public:
}; };
/** Constructor */ /** Constructor */
GxsForumsDialog::GxsForumsDialog(QWidget *parent) GxsForumsDialog::GxsForumsDialog(QWidget *parent) :
: GxsGroupFrameDialog(rsGxsForums, parent) GxsGroupFrameDialog(rsGxsForums, parent), mEventHandlerId(0)
{ {
mCountChildMsgs = true; mCountChildMsgs = true;
mEventHandlerId = 0;
// Needs to be asynced because this function is likely to be called by another thread!
rsEvents->registerEventsHandler(RsEventType::GXS_FORUMS, [this](std::shared_ptr<const RsEvent> event) { RsQThreadUtils::postToObject( [=]() { handleEvent_main_thread(event); }, this ); }, mEventHandlerId ); rsEvents->registerEventsHandler(
[this](std::shared_ptr<const RsEvent> event)
{ RsQThreadUtils::postToObject( [=]() { handleEvent_main_thread(event); }, this ); },
mEventHandlerId, RsEventType::GXS_FORUMS );
} }
void GxsForumsDialog::handleEvent_main_thread(std::shared_ptr<const RsEvent> event) void GxsForumsDialog::handleEvent_main_thread(std::shared_ptr<const RsEvent> event)

View File

@ -52,8 +52,10 @@ HashingStatus::HashingStatus(QWidget *parent)
hashloader->hide(); hashloader->hide();
statusHashing->hide(); statusHashing->hide();
mEventHandlerId=0; mEventHandlerId=0;
rsEvents->registerEventsHandler(RsEventType::SHARED_DIRECTORIES, [this](std::shared_ptr<const RsEvent> event) { handleEvent(event); }, mEventHandlerId ); rsEvents->registerEventsHandler(
[this](std::shared_ptr<const RsEvent> event) { handleEvent(event); },
mEventHandlerId, RsEventType::SHARED_DIRECTORIES );
} }
void HashingStatus::handleEvent(std::shared_ptr<const RsEvent> event) void HashingStatus::handleEvent(std::shared_ptr<const RsEvent> event)

View File

@ -1,7 +1,7 @@
/******************************************************************************* /*******************************************************************************
* util/RsGxsUpdateBroadcast.cpp * * util/RsGxsUpdateBroadcast.cpp *
* * * *
* Copyright (c) 2014 Retroshare Team <retroshare.project@gmail.com> * * Copyright (C) 2014-2020 Retroshare Team <contact@retroshare.cc> *
* * * *
* This program is free software: you can redistribute it and/or modify * * This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Affero General Public License as * * it under the terms of the GNU Affero General Public License as *
@ -22,6 +22,7 @@
#include "RsGxsUpdateBroadcast.h" #include "RsGxsUpdateBroadcast.h"
#include "gui/notifyqt.h" #include "gui/notifyqt.h"
#include "util/qtthreadsutils.h"
#include <retroshare/rsgxsifacehelper.h> #include <retroshare/rsgxsifacehelper.h>
@ -32,17 +33,20 @@
// now the update notify works through rsnotify and notifyqt // now the update notify works through rsnotify and notifyqt
// so the single instance per service is not really needed anymore // so the single instance per service is not really needed anymore
QMap<RsGxsIfaceHelper*, RsGxsUpdateBroadcast*> updateBroadcastMap; static QMap<RsGxsIfaceHelper*, RsGxsUpdateBroadcast*> updateBroadcastMap;
RsGxsUpdateBroadcast::RsGxsUpdateBroadcast(RsGxsIfaceHelper *ifaceImpl) : RsGxsUpdateBroadcast::RsGxsUpdateBroadcast(RsGxsIfaceHelper *ifaceImpl) :
QObject(NULL), mIfaceImpl(ifaceImpl) QObject(nullptr), mIfaceImpl(ifaceImpl), mEventHandlerId(0)
{ {
mEventHandlerId = 0; // forces initialization in registerEventsHandler() rsEvents->registerEventsHandler(
[this](std::shared_ptr<const RsEvent> event)
rsEvents->registerEventsHandler(RsEventType::GXS_CHANGES, [this](std::shared_ptr<const RsEvent> event) {
{ RsQThreadUtils::postToObject(
onChangesReceived(*dynamic_cast<const RsGxsChanges*>(event.get())); [=]()
}, mEventHandlerId ); { onChangesReceived(*dynamic_cast<const RsGxsChanges*>(event.get())); },
this );
},
mEventHandlerId, RsEventType::GXS_CHANGES );
} }
RsGxsUpdateBroadcast::~RsGxsUpdateBroadcast() RsGxsUpdateBroadcast::~RsGxsUpdateBroadcast()

View File

@ -31,7 +31,7 @@ struct RsGxsChanges;
typedef uint32_t TurtleRequestId ; typedef uint32_t TurtleRequestId ;
class RsGxsUpdateBroadcast : public QObject class RS_DEPRECATED RsGxsUpdateBroadcast : public QObject
{ {
Q_OBJECT Q_OBJECT