From 53e3177c2b19e39fa0e1397cfddf86aeb4cdba1a Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Sat, 14 Jan 2017 23:20:42 +0100 Subject: [PATCH 01/35] First experiments with GXS Mail Periodically pool GXS backend for new groups and subscribe to all. A group is created and an email can be sent to it but for some reason the group and and the email are not received by friends. --- libretroshare/src/libretroshare.pro | 6 +- libretroshare/src/serialiser/rsgxsmailitems.h | 278 ++++++++++++++++++ libretroshare/src/services/p3gxsmails.cpp | 180 ++++++++++++ libretroshare/src/services/p3gxsmails.h | 104 +++++++ retroshare.pri | 6 + 5 files changed, 573 insertions(+), 1 deletion(-) create mode 100644 libretroshare/src/serialiser/rsgxsmailitems.h create mode 100644 libretroshare/src/services/p3gxsmails.cpp create mode 100644 libretroshare/src/services/p3gxsmails.h diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index 551fbf335..e1617391a 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -852,7 +852,11 @@ gxsphotoshare { serialiser/rsphotoitems.cc \ } - +rs_gxs_mail +{ + HEADERS += serialiser/rsgxsmailitems.h services/p3gxsmails.h + SOURCES += services/p3gxsmails.cpp +} diff --git a/libretroshare/src/serialiser/rsgxsmailitems.h b/libretroshare/src/serialiser/rsgxsmailitems.h new file mode 100644 index 000000000..7508164e6 --- /dev/null +++ b/libretroshare/src/serialiser/rsgxsmailitems.h @@ -0,0 +1,278 @@ +#pragma once +/* + * GXS Mailing Service + * Copyright (C) 2016-2017 Gioacchino Mazzurco + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include + +#include "rsgxsitems.h" +#include "serialiser/rsbaseserial.h" +#include "serialiser/rstlvidset.h" +#include "retroshare/rsgxsflags.h" + +// TODO: move to rsserviceids.h +const uint16_t RS_SERVICE_TYPE_GXS_MAIL = 0x0230; + +enum GxsMailSubtypes +{ + GXS_MAIL_SUBTYPE_MAIL = 1, + GXS_MAIL_SUBTYPE_ACK, + GXS_MAIL_SUBTYPE_GROUP +}; + +struct RsGxsMailBaseItem : RsGxsMsgItem +{ + RsGxsMailBaseItem(GxsMailSubtypes subtype) : + RsGxsMsgItem(RS_SERVICE_TYPE_GXS_MAIL, (uint8_t)subtype), flags(0) {} + + enum RsGxsMailFlags { READ = 0x1 }; + uint8_t flags; + + /** + * @brief recipient_hint used instead of plain recipient id, so sender can + * decide the equilibrium between exposing the recipient and the cost of + * completely anonymize it. So a bunch of luky non recipient can conclude + * rapidly that they are not recipiend without trying to decrypt the + * message. + * + * To be able to decide how much metadata we disclose sending a message we + * send an hint instead of the recipient id in clear, the hint cannot be + * false (the recipient would discard the mail) but may be arbitrarly + * obscure like 0xFF...FF so potentially everyone could be the recipient, or + * may expose the complete recipient id or be a middle ground. + * To calculate arbitrary precise hint one do a bitwise OR of the recipients + * keys and an arbytrary salting mask, the more recipients has the mail and + * the more 1 bits has the mask the less accurate is the hint. + * This way the sender is able to adjust the metadata privacy needed for the + * message, in the more private case (recipient_hint == 0xFF...FF) no one + * has a clue about who is the actual recipient, while this imply the cost + * that every potencial recipient has to try to decrypt it to know if it is + * for herself. This way a bunch of non recipients can rapidly discover that + * the message is not directed to them without attempting it's decryption. + * + * To check if one id may be the recipient of the mail or not one need to + * bitwise compare the hint with the id, if at least one bit of the hint is + * 0 while the corrisponding bit in the id is 1 then the id cannot be the + * recipient of the mail. + * + * Note that by design one can prove that an id is not recipient of the mail + * but cannot prove it is. + * Also in the extreme case of using 0x00...00 as salt that is equivalent + * to not salting at all (aka the plain recipient id is used as hint) a + * malicious observer could not demostrate in a conclusive manner that the + * mail is directed to the actual recipient as the "apparently" + * corresponding hint may be fruit of a "luky" salting of another id. + */ + uint32_t recipient_hint; + + /** + * @brief maybe_recipient given an id and an hint check if they match + * @see recipient_hint + * @note this is not the final implementation as id and hint are not 32bit + * integers it is just to not forget how to verify the hint/id matching + * fastly with boolean ops + * @return true if the id may be recipient of the hint, false otherwise + */ + static bool maybe_recipient(uint32_t id, uint32_t hint) + { return (~id|hint) == 0xFFFFFFFF; } +}; + +struct RsGxsMailItem : RsGxsMailBaseItem +{ + RsGxsMailItem() : RsGxsMailBaseItem(GXS_MAIL_SUBTYPE_MAIL) {} + + RsTlvGxsIdSet recipients; + + /** + * @brief body of the email + * Should we ue MIME for compatibility with fido RS-email gateway? + * https://github.com/zeroreserve/fido + * https://github.com/RetroShare/fido + * https://en.wikipedia.org/wiki/MIME + */ + std::string body; + + void clear() + { + recipients.TlvClear(); + body.clear(); + } + std::ostream &print(std::ostream &out, uint16_t indent = 0) + { return recipients.print(out, indent) << body; } +}; + +struct RsGxsMailAckItem : RsGxsMailBaseItem +{ + RsGxsMailAckItem() : RsGxsMailBaseItem(GXS_MAIL_SUBTYPE_ACK) {} + RsGxsId recipient; + + void clear() { recipient.clear(); } + std::ostream &print(std::ostream &out, uint16_t /*indent = 0*/) + { return out << recipient.toStdString(); } +}; + +struct RsGxsMailGroupItem : RsGxsGrpItem +{ + RsGxsMailGroupItem() : + RsGxsGrpItem(RS_SERVICE_TYPE_GXS_MAIL, GXS_MAIL_SUBTYPE_GROUP) + { + meta.mGroupFlags = GXS_SERV::FLAG_PRIVACY_PUBLIC; + meta.mGroupName = "Mail"; + } + + void clear() {} + std::ostream &print(std::ostream &out, uint16_t /*indent = 0*/) + { return out; } +}; + +struct RsGxsMailSerializer : RsSerialType +{ + RsGxsMailSerializer() : RsSerialType( RS_PKT_VERSION_SERVICE, + RS_SERVICE_TYPE_GXS_MAIL ) {} + ~RsGxsMailSerializer() {} + + uint32_t size(RsItem* item) + { + uint32_t s = 8; // Header + + switch(item->PacketSubType()) + { + case GXS_MAIL_SUBTYPE_MAIL: + { + RsGxsMailItem* i = dynamic_cast(item); + if(i) + { + s += 4; // RsGxsMailBaseItem::recipient_hint + s += i->recipients.TlvSize(); + s += getRawStringSize(i->body); + } + break; + } + case GXS_MAIL_SUBTYPE_ACK: + { + RsGxsMailAckItem* i = dynamic_cast(item); + if(i) + { + s += 4; // RsGxsMailBaseItem::recipient_hint + s += 1; // RsGxsMailAckItem::read + s += i->recipient.serial_size(); + } + break; + } + case GXS_MAIL_SUBTYPE_GROUP: break; + default: return 0; + } + + std::cout << "RsGxsMailSerializer::size() " << item->PacketSubType() << " return " << s << std::endl; + return s; + } + + bool serialise(RsItem* item, void* data, uint32_t* size) + { + uint32_t tlvsize = RsGxsMailSerializer::size(item); + uint32_t offset = 0; + + if(*size < tlvsize) return false; + + *size = tlvsize; + + bool ok = true; + ok &= setRsItemHeader(data, tlvsize, item->PacketId(), tlvsize); + + /* skip the header */ + offset += 8; + + switch(item->PacketSubType()) + { + case GXS_MAIL_SUBTYPE_MAIL: + { + RsGxsMailItem* i = dynamic_cast(item); + if(i) + { + ok &= i->recipients.SetTlv(data, tlvsize, &offset); + ok &= setRawString(data, tlvsize, &offset, i->body); + } + break; + } + case GXS_MAIL_SUBTYPE_ACK: + { + RsGxsMailAckItem* i = dynamic_cast(item); + if(i) + { + ok &= i->recipient.serialise(data, tlvsize, offset); + ok &= setRawUInt8(data, tlvsize, &offset, i->flags); + } + break; + } + case GXS_MAIL_SUBTYPE_GROUP: break; + default: ok = false; break; + } + + return ok; + } + + RsItem* deserialise(void* data, uint32_t* size) + { + uint32_t rstype = getRsItemId(data); + uint32_t rssize = getRsItemSize(data); + uint32_t offset = 8; + + + if ( (RS_PKT_VERSION_SERVICE != getRsItemVersion(rstype)) || + (RS_SERVICE_TYPE_GXS_MAIL != getRsItemService(rstype)) || + (*size < rssize) ) + return NULL; + + *size = rssize; + bool ok = true; + RsItem* ret = NULL; + + switch (getRsItemSubType(rstype)) + { + case GXS_MAIL_SUBTYPE_MAIL: + { + RsGxsMailItem* i = new RsGxsMailItem(); + ok &= i->recipients.GetTlv(data, *size, &offset); + ok &= getRawString(data, *size, &offset, i->body); + ret = i; + break; + } + case GXS_MAIL_SUBTYPE_ACK: + { + RsGxsMailAckItem* i = new RsGxsMailAckItem(); + ok &= getRawUInt8(data, *size, &offset, &i->flags); + ok &= i->recipient.deserialise(data, *size, offset); + ret = i; + break; + } + case GXS_MAIL_SUBTYPE_GROUP: + { + ret = new RsGxsMailGroupItem(); + break; + } + default: + ok = false; + break; + } + + if(ok) return ret; + + delete ret; + return NULL; + } +}; + diff --git a/libretroshare/src/services/p3gxsmails.cpp b/libretroshare/src/services/p3gxsmails.cpp new file mode 100644 index 000000000..079186a05 --- /dev/null +++ b/libretroshare/src/services/p3gxsmails.cpp @@ -0,0 +1,180 @@ +/* + * GXS Mailing Service + * Copyright (C) 2016-2017 Gioacchino Mazzurco + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include "p3gxsmails.h" + + +bool p3GxsMails::sendEmail(const RsGxsId& own_gxsid, const RsGxsId& recipient, const std::string& body) +{ + std::cout << "p3GxsMails::sendEmail(...)" << std::endl; + + if(preferredGroupId.isNull()) + { + requestGroupsList(); + return false; + } + + RsGxsMailItem* m = new RsGxsMailItem; + m->meta.mAuthorId = own_gxsid; + m->meta.mGroupId = preferredGroupId; + m->recipients.ids.insert(recipient); + m->body = body; + + uint32_t token; + publishMsg(token, m); + + return true; +} + +void p3GxsMails::handleResponse(uint32_t token, uint32_t req_type) +{ + //std::cout << "p3GxsMails::handleResponse(" << token << ", " << req_type << ")" << std::endl; + switch (req_type) + { + case GROUPS_LIST: + { + std::vector groups; + getGroupData(token, groups); + + for( std::vector::iterator it = groups.begin(); + it != groups.end(); ++it ) + { + RsGxsGrpItem* grp = *it; + if(!IS_GROUP_SUBSCRIBED(grp->meta.mSubscribeFlags)) + { + std::cout << "p3GxsMails::handleResponse(...) subscribing to group: " << grp->meta.mGroupId << std::endl; + uint32_t token; + subscribeToGroup(token, grp->meta.mGroupId, true); + } + + supersedePreferredGroup(grp->meta.mGroupId); + } + + if(preferredGroupId.isNull()) + { + std::cout << "p3GxsMails::handleResponse(...) preferredGroupId.isNull()" << std::endl; + // TODO: Should check if we have friends before of doing this? + uint32_t token; + publishGroup(token, new RsGxsMailGroupItem()); + queueRequest(token, GROUP_CREATE); + } + + break; + } + case GROUP_CREATE: + { + std::cout << "p3GxsMails::handleResponse(...) GROUP_CREATE" << std::endl; + RsGxsGroupId grpId; + acknowledgeTokenGrp(token, grpId); + supersedePreferredGroup(grpId); + break; + } + default: + std::cout << "p3GxsMails::handleResponse(...) Unknown req_type: " << req_type << std::endl; + break; + } +/* + GxsMsgDataMap msgItems; + if(!RsGenExchange::getMsgData(token, msgItems)) + { + std::cerr << "p3GxsMails::handleResponse(...) Cannot get msg data. " + << "Something's weird." << std::endl; + } +*/ +} + +void p3GxsMails::service_tick() +{ + static int tc = 0; + ++tc; + if((tc % 100) == 0) + { +// std::cout << "p3GxsMails::service_tick() " << tc << " " +// << preferredGroupId << std::endl; + requestGroupsList(); + } + +#if 0 + if(tc == 500) + { + RsGxsId own_gxsid("d0df7474bdde0464679e6ef787890287"); + RsGxsId recipient("d060bea09dfa14883b5e6e517eb580cd"); + sendEmail(own_gxsid, recipient, "Ciao!"); + } +#endif + + GxsTokenQueue::checkRequests(); +} + +RsGenExchange::ServiceCreate_Return p3GxsMails::service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySet& /*keySet*/) +{ + std::cout << "p3GxsMails::service_CreateGroup(...) " << grpItem->meta.mGroupId << std::endl; + return SERVICE_CREATE_SUCCESS; +} + +void p3GxsMails::notifyChanges(std::vector& changes) +{ + std::cout << "p3GxsMails::notifyChanges(...)" << std::endl; + for( std::vector::const_iterator it = changes.begin(); + it != changes.end(); ++it ) + { + RsGxsGroupChange* grpChange = dynamic_cast(*it); + RsGxsMsgChange* msgChange = dynamic_cast(*it); + + if (grpChange) + { + typedef std::list::const_iterator itT; + for( itT it = grpChange->mGrpIdList.begin(); + it != grpChange->mGrpIdList.end(); ++it ) + { + const RsGxsGroupId& grpId = *it; + std::cout << "p3GxsMails::notifyChanges(...) got group " + << grpId << std::endl; + supersedePreferredGroup(grpId); + } + } + else if(msgChange) + { + typedef std::map > mT; + for( mT::const_iterator it = msgChange->msgChangeMap.begin(); + it != msgChange->msgChangeMap.end(); ++it ) + { + const RsGxsGroupId& grpId = it->first; + const std::vector& msgsIds = it->second; + typedef std::vector::const_iterator itT; + for(itT vit = msgsIds.begin(); vit != msgsIds.end(); ++vit) + { + const RsGxsMessageId& msgId = *vit; + std::cout << "p3GxsMails::notifyChanges(...) got " + << "new message " << msgId << " in group " + << grpId << std::endl; + } + } + } + } +} + +bool p3GxsMails::requestGroupsList() +{ + // std::cout << "p3GxsMails::requestGroupsList() GXS_REQUEST_TYPE_GROUP_META" << std::endl; + uint32_t token; + RsTokReqOptions opts; opts.mReqType = GXS_REQUEST_TYPE_GROUP_DATA; + RsGenExchange::getTokenService()->requestGroupInfo(token, 0xcaca, opts); + GxsTokenQueue::queueRequest(token, GROUPS_LIST); + return true; +} diff --git a/libretroshare/src/services/p3gxsmails.h b/libretroshare/src/services/p3gxsmails.h new file mode 100644 index 000000000..991b00b3a --- /dev/null +++ b/libretroshare/src/services/p3gxsmails.h @@ -0,0 +1,104 @@ +#pragma once +/* + * GXS Mailing Service + * Copyright (C) 2016-2017 Gioacchino Mazzurco + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include + +#include "retroshare/rsgxsifacetypes.h" // For RsGxsId, RsGxsCircleId +#include "gxs/gxstokenqueue.h" // For GxsTokenQueue +#include "serialiser/rsgxsmailitems.h" // For RS_SERVICE_TYPE_GXS_MAIL +#include "services/p3idservice.h" // For p3IdService + + +class p3GxsMails : public RsGenExchange, public GxsTokenQueue +{ +public: + p3GxsMails( RsGeneralDataService* gds, RsNetworkExchangeService* nes, + p3IdService *identities ) : + RsGenExchange( gds, nes, new RsGxsMailSerializer(), + RS_SERVICE_TYPE_GXS_MAIL, identities, + AuthenPolicy(), + RS_GXS_DEFAULT_MSG_STORE_PERIOD ), // TODO: Discuss with Cyril about this + GxsTokenQueue(this) {} + + /// Public interface + bool sendEmail( const RsGxsId& own_gxsid, const RsGxsId& recipient, + const std::string& body ); + + /** + * @see GxsTokenQueue::handleResponse(uint32_t token, uint32_t req_type) + */ + virtual void handleResponse(uint32_t token, uint32_t req_type); + + /// @see RsGenExchange::service_tick() + virtual void service_tick(); + + /// @see RsGenExchange::getServiceInfo() + virtual RsServiceInfo getServiceInfo() { return RsServiceInfo( RS_SERVICE_TYPE_GXS_MAIL, "GXS Mails", 0, 1, 0, 1 ); } + + /// @see RsGenExchange::service_CreateGroup(...) + RsGenExchange::ServiceCreate_Return service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySet&); + +protected: + /// @see RsGenExchange::notifyChanges(std::vector &changes) + void notifyChanges(std::vector &changes); + +private: + + /// @brief AuthenPolicy check nothing ATM TODO talk with Cyril how this should be + static uint32_t AuthenPolicy() { return 0; } + + /// Types to mark GXS queries and answhers + enum GxsReqResTypes { GROUPS_LIST, GROUP_CREATE }; + + RsGxsGroupId preferredGroupId; + + /// Request groups list to GXS backend. Async method. + bool requestGroupsList(); + + /** + * Check if current preferredGroupId is the best against potentialGrId, if + * the passed one is better update it. + * Useful when GXS backend notifies groups changes, or when a reponse to an + * async grop request (@see GXS_REQUEST_TYPE_GROUP_*) is received. + * @return true if preferredGroupId has been supeseded by potentialGrId + * false otherwise. + */ + bool inline supersedePreferredGroup(const RsGxsGroupId& potentialGrId) + { + std::cout << "supersedePreferredGroup(const RsGxsGroupId& potentialGrId) " << preferredGroupId << " Date: Sun, 15 Jan 2017 21:45:03 +0100 Subject: [PATCH 02/35] Initialize GXS mail service in rsinit.cc forgot in previous commit --- libretroshare/src/rsserver/rsinit.cc | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index 47036b691..837423d9c 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -82,6 +82,10 @@ #include "tcponudp/udpstunner.h" #endif // RS_USE_DHT_STUNNER +#ifdef RS_GXS_MAIL +# include "services/p3gxsmails.h" +#endif + // #define GPG_DEBUG // #define AUTHSSL_DEBUG // #define FIM_DEBUG @@ -1483,8 +1487,21 @@ int RsServer::StartupRetroShare() pqih->addService(gxschannels_ns, true); //pqih->addService(photo_ns, true); - // remove pword from memory - rsInitConfig->gxs_passwd = ""; +# ifdef RS_GXS_MAIL + RsGeneralDataService* gxsmail_ds = new RsDataService( + currGxsDir + "/", "gxsmails_db", RS_SERVICE_TYPE_GXS_MAIL, + NULL, rsInitConfig->gxs_passwd ); + p3GxsMails* mGxsMails = new p3GxsMails(gxsmail_ds, NULL, mGxsIdService); + RsGxsNetService* gxsmails_ns = new RsGxsNetService( + RS_SERVICE_TYPE_GXS_MAIL, gxschannels_ds, nxsMgr, mGxsMails, + mGxsMails->getServiceInfo(), mGxsIdService, mGxsCircles, + mGxsIdService, pgpAuxUtils ); + mGxsMails->setNetworkExchangeService(gxsmails_ns); + pqih->addService(gxsmails_ns, true); +# endif // RS_GXS_MAIL + + // remove pword from memory + rsInitConfig->gxs_passwd = ""; #endif // RS_ENABLE_GXS. @@ -1804,6 +1821,11 @@ int RsServer::StartupRetroShare() //createThread(*photo_ns); //createThread(*wire_ns); +# ifdef RS_GXS_MAIL + startServiceThread(mGxsMails, "gxs mail"); + startServiceThread(gxsmails_ns, "gxs mail ns"); +# endif // RS_GXS_MAIL + #endif // RS_ENABLE_GXS ftserver->StartupThreads(); From 38ab9a058f0773bf8fbf9097a68cc0657a446d7c Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Tue, 17 Jan 2017 18:30:06 +0100 Subject: [PATCH 03/35] Update initialization after rebase on top of 856819949760daa41ddc2c9ab199a3cbf4743884 --- libretroshare/src/rsserver/rsinit.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index 837423d9c..b57a8e477 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -1494,8 +1494,8 @@ int RsServer::StartupRetroShare() p3GxsMails* mGxsMails = new p3GxsMails(gxsmail_ds, NULL, mGxsIdService); RsGxsNetService* gxsmails_ns = new RsGxsNetService( RS_SERVICE_TYPE_GXS_MAIL, gxschannels_ds, nxsMgr, mGxsMails, - mGxsMails->getServiceInfo(), mGxsIdService, mGxsCircles, - mGxsIdService, pgpAuxUtils ); + mGxsMails->getServiceInfo(), mReputations, mGxsCircles, + mGxsIdService, pgpAuxUtils); mGxsMails->setNetworkExchangeService(gxsmails_ns); pqih->addService(gxsmails_ns, true); # endif // RS_GXS_MAIL From 0af9291e5438acf563b7bee156abd7399b230470 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Thu, 19 Jan 2017 00:32:37 +0100 Subject: [PATCH 04/35] Tiny fixes seems groups and messages propagate now --- libretroshare/src/rsserver/rsinit.cc | 3 ++- libretroshare/src/serialiser/rsgxsmailitems.h | 5 ++--- libretroshare/src/serialiser/rsserviceids.h | 1 + libretroshare/src/services/p3gxsmails.h | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index b57a8e477..c8a514043 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -1493,11 +1493,12 @@ int RsServer::StartupRetroShare() NULL, rsInitConfig->gxs_passwd ); p3GxsMails* mGxsMails = new p3GxsMails(gxsmail_ds, NULL, mGxsIdService); RsGxsNetService* gxsmails_ns = new RsGxsNetService( - RS_SERVICE_TYPE_GXS_MAIL, gxschannels_ds, nxsMgr, mGxsMails, + RS_SERVICE_TYPE_GXS_MAIL, gxsmail_ds, nxsMgr, mGxsMails, mGxsMails->getServiceInfo(), mReputations, mGxsCircles, mGxsIdService, pgpAuxUtils); mGxsMails->setNetworkExchangeService(gxsmails_ns); pqih->addService(gxsmails_ns, true); + mConfigMgr->addConfiguration("gxs_mail.cfg", gxsmails_ns); # endif // RS_GXS_MAIL // remove pword from memory diff --git a/libretroshare/src/serialiser/rsgxsmailitems.h b/libretroshare/src/serialiser/rsgxsmailitems.h index 7508164e6..2be002020 100644 --- a/libretroshare/src/serialiser/rsgxsmailitems.h +++ b/libretroshare/src/serialiser/rsgxsmailitems.h @@ -23,9 +23,8 @@ #include "serialiser/rsbaseserial.h" #include "serialiser/rstlvidset.h" #include "retroshare/rsgxsflags.h" +#include "retroshare/rsgxscircles.h" // For: GXS_CIRCLE_TYPE_PUBLIC -// TODO: move to rsserviceids.h -const uint16_t RS_SERVICE_TYPE_GXS_MAIL = 0x0230; enum GxsMailSubtypes { @@ -132,6 +131,7 @@ struct RsGxsMailGroupItem : RsGxsGrpItem { meta.mGroupFlags = GXS_SERV::FLAG_PRIVACY_PUBLIC; meta.mGroupName = "Mail"; + meta.mCircleType = GXS_CIRCLE_TYPE_PUBLIC; } void clear() {} @@ -177,7 +177,6 @@ struct RsGxsMailSerializer : RsSerialType default: return 0; } - std::cout << "RsGxsMailSerializer::size() " << item->PacketSubType() << " return " << s << std::endl; return s; } diff --git a/libretroshare/src/serialiser/rsserviceids.h b/libretroshare/src/serialiser/rsserviceids.h index 475d92595..1307ec53a 100644 --- a/libretroshare/src/serialiser/rsserviceids.h +++ b/libretroshare/src/serialiser/rsserviceids.h @@ -82,6 +82,7 @@ const uint16_t RS_SERVICE_GXS_TYPE_GXSCIRCLE = 0x0218; // not gxs, but used with identities. const uint16_t RS_SERVICE_GXS_TYPE_REPUTATION = 0x0219; const uint16_t RS_SERVICE_TYPE_GXS_RECOGN = 0x0220; +const uint16_t RS_SERVICE_TYPE_GXS_MAIL = 0x0230; // Experimental Services. /* DSDV Testing at the moment - Service Only */ diff --git a/libretroshare/src/services/p3gxsmails.h b/libretroshare/src/services/p3gxsmails.h index 991b00b3a..0a87d1575 100644 --- a/libretroshare/src/services/p3gxsmails.h +++ b/libretroshare/src/services/p3gxsmails.h @@ -81,7 +81,7 @@ private: */ bool inline supersedePreferredGroup(const RsGxsGroupId& potentialGrId) { - std::cout << "supersedePreferredGroup(const RsGxsGroupId& potentialGrId) " << preferredGroupId << " Date: Mon, 30 Jan 2017 15:18:12 +0100 Subject: [PATCH 05/35] GxsMail implemented RSA encrypted mails sending Add notice about param not being checked in GxsSecurity Use proper types for RsGenExchange::getMsg* params Implement bitwise or and not operators for t_RsGenericIdType GxsMail unsubscribe old unused groups GxsMail initial work on supporting client services Implemented p3IdService::encryptData(...) for multiple recipients --- libretroshare/src/gxs/gxssecurity.h | 5 +- libretroshare/src/gxs/rsgenexchange.cc | 5 +- libretroshare/src/gxs/rsgenexchange.h | 8 +- libretroshare/src/libretroshare.pro | 2 +- libretroshare/src/retroshare/rsids.h | 16 + libretroshare/src/retroshare/rstokenservice.h | 8 +- libretroshare/src/rsserver/rsinit.cc | 2 +- .../src/serialiser/rsgxsmailitems.cc | 96 ++++++ libretroshare/src/serialiser/rsgxsmailitems.h | 196 ++++++------- libretroshare/src/services/p3gxsmails.cpp | 277 ++++++++++++++---- libretroshare/src/services/p3gxsmails.h | 106 +++++-- libretroshare/src/services/p3idservice.cc | 93 +++++- libretroshare/src/services/p3idservice.h | 38 ++- 13 files changed, 655 insertions(+), 197 deletions(-) create mode 100644 libretroshare/src/serialiser/rsgxsmailitems.cc diff --git a/libretroshare/src/gxs/gxssecurity.h b/libretroshare/src/gxs/gxssecurity.h index b19f81302..129d07147 100644 --- a/libretroshare/src/gxs/gxssecurity.h +++ b/libretroshare/src/gxs/gxssecurity.h @@ -35,9 +35,10 @@ /*! - * This contains functionality for performing security - * operations needed to validate data received in RsGenExchange + * This contains functionality for performing basic security operations needed + * in RsGenExchange operations. * Also has routine for creating security objects around msgs and groups + * TODO: Those functions doesn't do param checking! */ class GxsSecurity { diff --git a/libretroshare/src/gxs/rsgenexchange.cc b/libretroshare/src/gxs/rsgenexchange.cc index aa098a1dc..1b2cb3f8f 100644 --- a/libretroshare/src/gxs/rsgenexchange.cc +++ b/libretroshare/src/gxs/rsgenexchange.cc @@ -1332,7 +1332,7 @@ bool RsGenExchange::getGroupData(const uint32_t &token, std::vector - bool getMsgDataT(const uint32_t &token, std::map >& msgItems) + bool getMsgDataT( uint32_t token, std::map >& msgItems) { GxsMsgDataMap msgData; bool ok = getMsgData(token, msgData); @@ -365,7 +365,7 @@ public: * @param token token to be redeemed for message item retrieval * @param msgItems */ - bool getMsgRelatedData(const uint32_t &token, GxsMsgRelatedDataMap& msgItems); + bool getMsgRelatedData(uint32_t token, GxsMsgRelatedDataMap& msgItems); protected: diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index e1617391a..d94d7005b 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -855,7 +855,7 @@ gxsphotoshare { rs_gxs_mail { HEADERS += serialiser/rsgxsmailitems.h services/p3gxsmails.h - SOURCES += services/p3gxsmails.cpp + SOURCES += serialiser/rsgxsmailitems.cc services/p3gxsmails.cpp } diff --git a/libretroshare/src/retroshare/rsids.h b/libretroshare/src/retroshare/rsids.h index db842ab21..22528043b 100644 --- a/libretroshare/src/retroshare/rsids.h +++ b/libretroshare/src/retroshare/rsids.h @@ -94,6 +94,22 @@ template c inline bool operator==(const t_RsGenericIdType& fp) const { return !memcmp(bytes,fp.bytes,ID_SIZE_IN_BYTES) ; } inline bool operator!=(const t_RsGenericIdType& fp) const { return !!memcmp(bytes,fp.bytes,ID_SIZE_IN_BYTES); } inline bool operator< (const t_RsGenericIdType& fp) const { return (memcmp(bytes,fp.bytes,ID_SIZE_IN_BYTES) < 0) ; } + inline t_RsGenericIdType + operator~ () const + { + t_RsGenericIdType ret; + for(uint32_t i=0; i < ID_SIZE_IN_BYTES; ++i) + ret.bytes[i] = ~bytes[i]; + return ret; + } + inline t_RsGenericIdType + operator| (const t_RsGenericIdType& fp) const + { + t_RsGenericIdType ret; + for(uint32_t i=0; i < ID_SIZE_IN_BYTES; ++i) + ret.bytes[i] = bytes[i] | fp.bytes[i]; + return ret; + } inline bool isNull() const { diff --git a/libretroshare/src/retroshare/rstokenservice.h b/libretroshare/src/retroshare/rstokenservice.h index c55213965..79097cc5c 100644 --- a/libretroshare/src/retroshare/rstokenservice.h +++ b/libretroshare/src/retroshare/rstokenservice.h @@ -137,7 +137,7 @@ public: /*! * Use this to request group related information - * @param token The token returned for the request, store this value to pool for request completion + * @param token The token returned for the request, store this value to poll for request completion * @param ansType The type of result (e.g. group data, meta, ids) * @param opts Additional option that affect outcome of request. Please see specific services, for valid values * @param groupIds group id to request info for @@ -147,7 +147,7 @@ public: /*! * Use this to request all group related info - * @param token The token returned for the request, store this value to pool for request completion + * @param token The token returned for the request, store this value to poll for request completion * @param ansType The type of result (e.g. group data, meta, ids) * @param opts Additional option that affect outcome of request. Please see specific services, for valid values * @return @@ -155,7 +155,7 @@ public: virtual bool requestGroupInfo(uint32_t &token, uint32_t ansType, const RsTokReqOptions &opts) = 0; /*! - * Use this to get msg related information, store this value to pole for request completion + * Use this to get msg related information, store this value to poll for request completion * @param token The token returned for the request * @param ansType The type of result wanted * @param opts Additional option that affect outcome of request. Please see specific services, for valid values @@ -165,7 +165,7 @@ public: virtual bool requestMsgInfo(uint32_t &token, uint32_t ansType, const RsTokReqOptions &opts, const GxsMsgReq& msgIds) = 0; /*! - * Use this to get msg related information, store this value to pole for request completion + * Use this to get msg related information, store this value to poll for request completion * @param token The token returned for the request * @param ansType The type of result wanted * @param opts Additional option that affect outcome of request. Please see specific services, for valid values diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index c8a514043..3eb9ba146 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -1491,7 +1491,7 @@ int RsServer::StartupRetroShare() RsGeneralDataService* gxsmail_ds = new RsDataService( currGxsDir + "/", "gxsmails_db", RS_SERVICE_TYPE_GXS_MAIL, NULL, rsInitConfig->gxs_passwd ); - p3GxsMails* mGxsMails = new p3GxsMails(gxsmail_ds, NULL, mGxsIdService); + p3GxsMails* mGxsMails = new p3GxsMails(gxsmail_ds, NULL, *mGxsIdService); RsGxsNetService* gxsmails_ns = new RsGxsNetService( RS_SERVICE_TYPE_GXS_MAIL, gxsmail_ds, nxsMgr, mGxsMails, mGxsMails->getServiceInfo(), mReputations, mGxsCircles, diff --git a/libretroshare/src/serialiser/rsgxsmailitems.cc b/libretroshare/src/serialiser/rsgxsmailitems.cc new file mode 100644 index 000000000..a3d624b44 --- /dev/null +++ b/libretroshare/src/serialiser/rsgxsmailitems.cc @@ -0,0 +1,96 @@ +/* + * GXS Mailing Service + * Copyright (C) 2016-2017 Gioacchino Mazzurco + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include "serialiser/rsgxsmailitems.h" + +const RsGxsId RsGxsMailBaseItem::allRecipientsHint("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); + + +bool RsGxsMailBaseItem::serialize(uint8_t* data, uint32_t size, + uint32_t& offset) const +{ + bool ok = setRsItemHeader(data, size, PacketId(), size); + ok = ok && (offset += 8); // Take in account the header + ok = ok && setRawUInt8(data, size, &offset, cryptoType); + ok = ok && recipientsHint.serialise(data, size, offset); + return ok; +} + +bool RsGxsMailBaseItem::deserialize(const uint8_t* data, uint32_t& size, + uint32_t& offset) +{ + void* dataPtr = reinterpret_cast(const_cast(data)); + uint32_t rssize = getRsItemSize(dataPtr); + uint32_t roffset = offset + 8; + bool ok = rssize <= size; + uint8_t crType; + ok = ok && getRawUInt8(dataPtr, rssize, &offset, &crType); + cryptoType = static_cast(crType); + ok = ok && recipientsHint.deserialise(dataPtr, rssize, roffset); + if(ok) { size = rssize; offset = roffset; } + else size = 0; + return ok; +} + +std::ostream&RsGxsMailBaseItem::print(std::ostream& out, uint16_t) +{ return out; } + +bool RsGxsMailSerializer::serialise(RsItem* item, void* data, uint32_t* size) +{ + uint32_t itemSize = RsGxsMailSerializer::size(item); + if(*size < itemSize) + { + std::cout << "RsGxsMailSerializer::serialise(...) failed due to wrong size: " + << size << " < " << itemSize << std::endl; + return false; + } + + uint8_t* dataPtr = reinterpret_cast(data); + bool ok = true; + switch(item->PacketSubType()) + { + case GXS_MAIL_SUBTYPE_MAIL: + { + uint32_t offset = 0; + RsGxsMailItem* i = dynamic_cast(item); + ok = ok && i->serialize(dataPtr, itemSize, offset); + break; + } + case GXS_MAIL_SUBTYPE_ACK: + { + RsGxsMailAckItem* i = dynamic_cast(item); + ok = ok && setRsItemHeader(data, itemSize, item->PacketId(), itemSize); + uint32_t offset = 8; + ok = ok && i->recipient.serialise(data, itemSize, offset); + break; + } + case GXS_MAIL_SUBTYPE_GROUP: + ok = ok && setRsItemHeader(data, itemSize, item->PacketId(), itemSize); + break; + default: ok = false; break; + } + + if(ok) + { + *size = itemSize; + return true; + } + + std::cout << "RsGxsMailSerializer::serialise(...) failed!" << std::endl; + return false; +} diff --git a/libretroshare/src/serialiser/rsgxsmailitems.h b/libretroshare/src/serialiser/rsgxsmailitems.h index 2be002020..f57439f43 100644 --- a/libretroshare/src/serialiser/rsgxsmailitems.h +++ b/libretroshare/src/serialiser/rsgxsmailitems.h @@ -24,28 +24,36 @@ #include "serialiser/rstlvidset.h" #include "retroshare/rsgxsflags.h" #include "retroshare/rsgxscircles.h" // For: GXS_CIRCLE_TYPE_PUBLIC +#include "services/p3idservice.h" - -enum GxsMailSubtypes +/// Values must fit into uint8_t +enum GxsMailItemsSubtypes { - GXS_MAIL_SUBTYPE_MAIL = 1, - GXS_MAIL_SUBTYPE_ACK, - GXS_MAIL_SUBTYPE_GROUP + GXS_MAIL_SUBTYPE_MAIL = 1, + GXS_MAIL_SUBTYPE_ACK = 2, + GXS_MAIL_SUBTYPE_GROUP = 3 }; struct RsGxsMailBaseItem : RsGxsMsgItem { - RsGxsMailBaseItem(GxsMailSubtypes subtype) : - RsGxsMsgItem(RS_SERVICE_TYPE_GXS_MAIL, (uint8_t)subtype), flags(0) {} + RsGxsMailBaseItem(GxsMailItemsSubtypes subtype) : + RsGxsMsgItem( RS_SERVICE_TYPE_GXS_MAIL, + static_cast(subtype) ) {} - enum RsGxsMailFlags { READ = 0x1 }; - uint8_t flags; + /// Values must fit into uint8_t + enum EncryptionMode + { + CLEAR_TEXT = 1, + RSA = 2, + UNDEFINED_ENCRYPTION = 250 + }; + EncryptionMode cryptoType; /** - * @brief recipient_hint used instead of plain recipient id, so sender can + * @brief recipientsHint used instead of plain recipient id, so sender can * decide the equilibrium between exposing the recipient and the cost of * completely anonymize it. So a bunch of luky non recipient can conclude - * rapidly that they are not recipiend without trying to decrypt the + * rapidly that they are not the recipient without trying to decrypt the * message. * * To be able to decide how much metadata we disclose sending a message we @@ -54,10 +62,10 @@ struct RsGxsMailBaseItem : RsGxsMsgItem * obscure like 0xFF...FF so potentially everyone could be the recipient, or * may expose the complete recipient id or be a middle ground. * To calculate arbitrary precise hint one do a bitwise OR of the recipients - * keys and an arbytrary salting mask, the more recipients has the mail and - * the more 1 bits has the mask the less accurate is the hint. + * keys and an arbitrary salt, the more recipients has the mail and the more + * 1 bits has the salt the less accurate is the hint. * This way the sender is able to adjust the metadata privacy needed for the - * message, in the more private case (recipient_hint == 0xFF...FF) no one + * message, in the more private case (recipientsHint == 0xFFF...FFF) no one * has a clue about who is the actual recipient, while this imply the cost * that every potencial recipient has to try to decrypt it to know if it is * for herself. This way a bunch of non recipients can rapidly discover that @@ -76,42 +84,75 @@ struct RsGxsMailBaseItem : RsGxsMsgItem * mail is directed to the actual recipient as the "apparently" * corresponding hint may be fruit of a "luky" salting of another id. */ - uint32_t recipient_hint; + RsGxsId recipientsHint; + + void inline saltRecipientHint(const RsGxsId& salt) + { saltRecipientHint(recipientsHint, salt); } + + void static inline saltRecipientHint(RsGxsId& hint, const RsGxsId& salt) + { hint = hint | salt; } /** - * @brief maybe_recipient given an id and an hint check if they match - * @see recipient_hint + * @brief maybeRecipient given an id and an hint check if they match + * @see recipientHint * @note this is not the final implementation as id and hint are not 32bit * integers it is just to not forget how to verify the hint/id matching * fastly with boolean ops * @return true if the id may be recipient of the hint, false otherwise */ - static bool maybe_recipient(uint32_t id, uint32_t hint) - { return (~id|hint) == 0xFFFFFFFF; } + bool static inline maybeRecipient(const RsGxsId& hint, const RsGxsId& id) + { return (~id|hint) == allRecipientsHint; } + + const static RsGxsId allRecipientsHint; + + void inline clear() + { + cryptoType = UNDEFINED_ENCRYPTION; + recipientsHint.clear(); + meta = RsMsgMetaData(); + } + + static uint32_t inline size() + { + return 8 + // Header + 1 + // cryptoType + RsGxsId::serial_size(); // recipientsHint + } + bool serialize(uint8_t* data, uint32_t size, uint32_t& offset) const; + bool deserialize(const uint8_t* data, uint32_t& size, uint32_t& offset); + std::ostream &print(std::ostream &out, uint16_t /*indent = 0*/); }; struct RsGxsMailItem : RsGxsMailBaseItem { - RsGxsMailItem() : RsGxsMailBaseItem(GXS_MAIL_SUBTYPE_MAIL) {} + RsGxsMailItem(GxsMailItemsSubtypes subtype) : + RsGxsMailBaseItem(subtype) {} + RsGxsMailItem() : + RsGxsMailBaseItem(GXS_MAIL_SUBTYPE_MAIL) {} - RsTlvGxsIdSet recipients; + /** This should travel encrypted, unless EncryptionMode::CLEAR_TEXT + * is specified */ + std::vector payload; - /** - * @brief body of the email - * Should we ue MIME for compatibility with fido RS-email gateway? - * https://github.com/zeroreserve/fido - * https://github.com/RetroShare/fido - * https://en.wikipedia.org/wiki/MIME - */ - std::string body; - - void clear() + uint32_t size() const { return RsGxsMailBaseItem::size() + payload.size(); } + bool serialize(uint8_t* data, uint32_t size, uint32_t& offset) const { - recipients.TlvClear(); - body.clear(); + return size < MAX_SIZE + && RsGxsMailBaseItem::serialize(data, size, offset) + && memcpy(data+offset, &payload[0], payload.size()); } - std::ostream &print(std::ostream &out, uint16_t indent = 0) - { return recipients.print(out, indent) << body; } + bool deserialize(const uint8_t* data, uint32_t& size, uint32_t& offset) + { + uint32_t bsz = RsGxsMailBaseItem::size(); + uint32_t psz = size - bsz; + return size < MAX_SIZE && size >= bsz + && RsGxsMailBaseItem::deserialize(data, size, offset) + && (payload.resize(psz), memcpy(&payload[0], data+offset, psz)); + } + void clear() { RsGxsMailBaseItem::clear(); payload.clear(); } + + /// Maximum mail size in bytes 10 MiB is more than anything sane can need + const static uint32_t MAX_SIZE = 10*8*1024*1024; }; struct RsGxsMailAckItem : RsGxsMailBaseItem @@ -147,19 +188,13 @@ struct RsGxsMailSerializer : RsSerialType uint32_t size(RsItem* item) { - uint32_t s = 8; // Header - + uint32_t sz = 0; switch(item->PacketSubType()) { case GXS_MAIL_SUBTYPE_MAIL: { RsGxsMailItem* i = dynamic_cast(item); - if(i) - { - s += 4; // RsGxsMailBaseItem::recipient_hint - s += i->recipients.TlvSize(); - s += getRawStringSize(i->body); - } + if(i) sz = i->size(); break; } case GXS_MAIL_SUBTYPE_ACK: @@ -167,74 +202,36 @@ struct RsGxsMailSerializer : RsSerialType RsGxsMailAckItem* i = dynamic_cast(item); if(i) { - s += 4; // RsGxsMailBaseItem::recipient_hint - s += 1; // RsGxsMailAckItem::read - s += i->recipient.serial_size(); + sz = 8; // Header + sz += 4; // RsGxsMailBaseItem::recipient_hint + sz += 1; // RsGxsMailAckItem::read + sz += i->recipient.serial_size(); } break; } - case GXS_MAIL_SUBTYPE_GROUP: break; - default: return 0; + case GXS_MAIL_SUBTYPE_GROUP: sz = 8; break; + default: break; } - return s; + return sz; } - bool serialise(RsItem* item, void* data, uint32_t* size) - { - uint32_t tlvsize = RsGxsMailSerializer::size(item); - uint32_t offset = 0; - - if(*size < tlvsize) return false; - - *size = tlvsize; - - bool ok = true; - ok &= setRsItemHeader(data, tlvsize, item->PacketId(), tlvsize); - - /* skip the header */ - offset += 8; - - switch(item->PacketSubType()) - { - case GXS_MAIL_SUBTYPE_MAIL: - { - RsGxsMailItem* i = dynamic_cast(item); - if(i) - { - ok &= i->recipients.SetTlv(data, tlvsize, &offset); - ok &= setRawString(data, tlvsize, &offset, i->body); - } - break; - } - case GXS_MAIL_SUBTYPE_ACK: - { - RsGxsMailAckItem* i = dynamic_cast(item); - if(i) - { - ok &= i->recipient.serialise(data, tlvsize, offset); - ok &= setRawUInt8(data, tlvsize, &offset, i->flags); - } - break; - } - case GXS_MAIL_SUBTYPE_GROUP: break; - default: ok = false; break; - } - - return ok; - } + bool serialise(RsItem* item, void* data, uint32_t* size); RsItem* deserialise(void* data, uint32_t* size) { uint32_t rstype = getRsItemId(data); uint32_t rssize = getRsItemSize(data); - uint32_t offset = 8; + uint8_t pktv = getRsItemVersion(rstype); + uint16_t srvc = getRsItemService(rstype); - - if ( (RS_PKT_VERSION_SERVICE != getRsItemVersion(rstype)) || - (RS_SERVICE_TYPE_GXS_MAIL != getRsItemService(rstype)) || + if ( (RS_PKT_VERSION_SERVICE != pktv) || // 0x02 + (RS_SERVICE_TYPE_GXS_MAIL != srvc) || // 0x0230 = 560 (*size < rssize) ) + { + print_stacktrace(); return NULL; + } *size = rssize; bool ok = true; @@ -245,15 +242,16 @@ struct RsGxsMailSerializer : RsSerialType case GXS_MAIL_SUBTYPE_MAIL: { RsGxsMailItem* i = new RsGxsMailItem(); - ok &= i->recipients.GetTlv(data, *size, &offset); - ok &= getRawString(data, *size, &offset, i->body); + uint32_t offset = 0; + const uint8_t* dataPtr = reinterpret_cast(data); + ok = ok && i->deserialize(dataPtr, *size, offset); ret = i; break; } case GXS_MAIL_SUBTYPE_ACK: { RsGxsMailAckItem* i = new RsGxsMailAckItem(); - ok &= getRawUInt8(data, *size, &offset, &i->flags); + uint32_t offset = 0; ok &= i->recipient.deserialise(data, *size, offset); ret = i; break; diff --git a/libretroshare/src/services/p3gxsmails.cpp b/libretroshare/src/services/p3gxsmails.cpp index 079186a05..63a07f4d3 100644 --- a/libretroshare/src/services/p3gxsmails.cpp +++ b/libretroshare/src/services/p3gxsmails.cpp @@ -17,30 +17,137 @@ */ #include "p3gxsmails.h" +#include "util/stacktrace.h" -bool p3GxsMails::sendEmail(const RsGxsId& own_gxsid, const RsGxsId& recipient, const std::string& body) +bool p3GxsMails::sendMail( GxsMailsClient::GxsMailSubServices service, + const RsGxsId& own_gxsid, const RsGxsId& recipient, + const uint8_t* data, uint32_t size, + RsGxsMailBaseItem::EncryptionMode cm) +{ + std::vector recipients; + recipients.push_back(&recipient); + return sendMail(service, own_gxsid, recipients, data, size, cm); +} + +bool p3GxsMails::sendMail( GxsMailsClient::GxsMailSubServices service, + const RsGxsId& own_gxsid, + const std::vector& recipients, + const uint8_t* data, uint32_t size, + RsGxsMailBaseItem::EncryptionMode cm ) { std::cout << "p3GxsMails::sendEmail(...)" << std::endl; if(preferredGroupId.isNull()) { - requestGroupsList(); + requestGroupsData(); + std::cerr << "p3GxsMails::sendEmail(...) preferredGroupId.isNull()!" + << std::endl; return false; } - RsGxsMailItem* m = new RsGxsMailItem; - m->meta.mAuthorId = own_gxsid; - m->meta.mGroupId = preferredGroupId; - m->recipients.ids.insert(recipient); - m->body = body; + if(!idService.isOwnId(own_gxsid)) + { + std::cerr << "p3GxsMails::sendEmail(...) isOwnId(own_gxsid) false!" + << std::endl; + return false; + } + + std::set rcps; + typedef std::vector::const_iterator itT; + for(itT it = recipients.begin(); it != recipients.end(); it++) + { + const RsGxsId* gId = *it; + + if(!gId || gId->isNull()) + { + std::cerr << "p3GxsMails::sendEmail(...) got invalid recipient" + << std::endl; + print_stacktrace(); + return false; + } + + rcps.insert(*gId); + } + if(rcps.empty()) + { + std::cerr << "p3GxsMails::sendEmail(...) got no recipients" + << std::endl; + print_stacktrace(); + return false; + } + + RsGxsMailItem* item = new RsGxsMailItem(); + + // Public metadata + item->meta.mAuthorId = own_gxsid; + item->meta.mGroupId = preferredGroupId; + + typedef std::set::const_iterator siT; + for(siT it = rcps.begin(); it != rcps.end(); ++it) + item->saltRecipientHint(*it); + + // If there is jut one recipient salt with a random id to avoid leaking it + if(rcps.size() == 1) item->saltRecipientHint(RsGxsId::random()); + + + /* At this point we do a lot of memory copying, it doesn't look pretty but + * ATM haven't thinked of an elegant way to have the GxsMailSubServices + * travelling encrypted withuot copying memory around or responsabilize the + * client service to embed it in data array that is awful */ + + uint16_t serv = static_cast(service); + uint32_t clearTextPldSize = size+2; + item->payload.resize(clearTextPldSize); + uint32_t _discard = 0; + setRawUInt16(&item->payload[0], clearTextPldSize, &_discard, serv); + memcpy(&item->payload[2], data, size); + + switch (cm) + { + case RsGxsMailBaseItem::CLEAR_TEXT: + { + std::cerr << "p3GxsMails::sendMail(...) you are sending a mail without" + << " encryption, everyone can read it!" << std::endl; + print_stacktrace(); + break; + } + case RsGxsMailBaseItem::RSA: + { + uint8_t* encryptedData = NULL; + uint32_t encryptedSize = 0; + uint32_t encryptError = 0; + if( idService.encryptData( &item->payload[0], clearTextPldSize, + encryptedData, encryptedSize, + rcps, true, encryptError ) ) + { + item->payload.resize(encryptedSize); + memcpy(&item->payload[0], encryptedData, encryptedSize); + free(encryptedData); + break; + } + else + { + std::cerr << "p3GxsMails::sendMail(...) RSA encryption failed! " + << "error_status: " << encryptError << std::endl; + print_stacktrace(); + return false; + } + } + case RsGxsMailBaseItem::UNDEFINED_ENCRYPTION: + default: + std::cerr << "p3GxsMails::sendMail(...) attempt to send mail with wrong" + << " EncryptionMode " << cm << " dropping mail!" << std::endl; + print_stacktrace(); + return false; + } uint32_t token; - publishMsg(token, m); - + publishMsg(token, item); return true; } + void p3GxsMails::handleResponse(uint32_t token, uint32_t req_type) { //std::cout << "p3GxsMails::handleResponse(" << token << ", " << req_type << ")" << std::endl; @@ -54,21 +161,37 @@ void p3GxsMails::handleResponse(uint32_t token, uint32_t req_type) for( std::vector::iterator it = groups.begin(); it != groups.end(); ++it ) { - RsGxsGrpItem* grp = *it; - if(!IS_GROUP_SUBSCRIBED(grp->meta.mSubscribeFlags)) - { - std::cout << "p3GxsMails::handleResponse(...) subscribing to group: " << grp->meta.mGroupId << std::endl; - uint32_t token; - subscribeToGroup(token, grp->meta.mGroupId, true); - } + /* For each group check if it is better candidate then + * preferredGroupId, if it is supplant it and subscribe if it is not + * subscribed yet. + * Otherwise if it has recent messages subscribe. + * If the group was already subscribed has no recent messages + * unsubscribe. + */ - supersedePreferredGroup(grp->meta.mGroupId); + const RsGroupMetaData& meta = (*it)->meta; + bool subscribed = IS_GROUP_SUBSCRIBED(meta.mSubscribeFlags); + bool old = olderThen( meta.mLastPost, + UNUSED_GROUP_UNSUBSCRIBE_INTERVAL ); + bool supersede = supersedePreferredGroup(meta.mGroupId); + uint32_t token; + + if( !subscribed && ( !old || supersede )) + subscribeToGroup(token, meta.mGroupId, true); + else if( subscribed && old ) + subscribeToGroup(token, meta.mGroupId, false); } if(preferredGroupId.isNull()) { - std::cout << "p3GxsMails::handleResponse(...) preferredGroupId.isNull()" << std::endl; - // TODO: Should check if we have friends before of doing this? + /* This is true only at first run when we haven't received mail + * distribuition groups from friends + * TODO: We should check if we have some connected firend too, to + * avoid to create yet another never used mail distribution group. + */ + + std::cerr << "p3GxsMails::handleResponse(...) preferredGroupId.isNu" + << "ll() let's create a new group." << std::endl; uint32_t token; publishGroup(token, new RsGxsMailGroupItem()); queueRequest(token, GROUP_CREATE); @@ -78,45 +201,86 @@ void p3GxsMails::handleResponse(uint32_t token, uint32_t req_type) } case GROUP_CREATE: { - std::cout << "p3GxsMails::handleResponse(...) GROUP_CREATE" << std::endl; + std::cerr << "p3GxsMails::handleResponse(...) GROUP_CREATE" << std::endl; RsGxsGroupId grpId; acknowledgeTokenGrp(token, grpId); supersedePreferredGroup(grpId); break; } + case MAILS_UPDATE: + { + std::cout << "p3GxsMails::handleResponse(...) MAILS_UPDATE" << std::endl; + typedef std::map > GxsMsgDataMap; + GxsMsgDataMap gpMsgMap; + getMsgData(token, gpMsgMap); + for ( GxsMsgDataMap::iterator gIt = gpMsgMap.begin(); + gIt != gpMsgMap.end(); ++gIt ) + { + typedef std::vector vT; + vT& mv(gIt->second); + for( vT::const_iterator mIt = mv.begin(); mIt != mv.end(); ++mIt ) + { + RsGxsMsgItem* it = *mIt; + std::cout << "p3GxsMails::handleResponse(...) MAILS_UPDATE " + << (uint32_t)it->PacketSubType() << std::endl; + switch(it->PacketSubType()) + { + case GXS_MAIL_SUBTYPE_MAIL: + { + RsGxsMailItem* msg = dynamic_cast(it); + if(msg) + { + std::cout << "p3GxsMails::handleResponse(...) " + << "GXS_MAIL_SUBTYPE_MAIL got recipientsHint: " + << msg->recipientsHint << " cryptoType: " + << (uint32_t)msg->cryptoType + << " payload size: " << msg->payload.size() + << std::endl; + } + break; + } + default: + std::cerr << "p3GxsMails::handleResponse(...) MAILS_UPDATE " + << "Unknown mail subtype : " + << it->PacketSubType() << std::endl; + break; + } + } + } + } default: - std::cout << "p3GxsMails::handleResponse(...) Unknown req_type: " << req_type << std::endl; + std::cerr << "p3GxsMails::handleResponse(...) Unknown req_type: " + << req_type << std::endl; break; } -/* - GxsMsgDataMap msgItems; - if(!RsGenExchange::getMsgData(token, msgItems)) - { - std::cerr << "p3GxsMails::handleResponse(...) Cannot get msg data. " - << "Something's weird." << std::endl; - } -*/ } void p3GxsMails::service_tick() { static int tc = 0; ++tc; - if((tc % 100) == 0) - { -// std::cout << "p3GxsMails::service_tick() " << tc << " " -// << preferredGroupId << std::endl; - requestGroupsList(); - } -#if 0 + if(((tc % 1000) == 0) || (tc == 50)) requestGroupsData(); + if(tc == 500) { - RsGxsId own_gxsid("d0df7474bdde0464679e6ef787890287"); - RsGxsId recipient("d060bea09dfa14883b5e6e517eb580cd"); - sendEmail(own_gxsid, recipient, "Ciao!"); + RsGxsId gxsidA("d0df7474bdde0464679e6ef787890287"); + RsGxsId gxsidB("d060bea09dfa14883b5e6e517eb580cd"); + if(idService.isOwnId(gxsidA)) + { + std::string ciao("CiAone!"); + sendMail( GxsMailsClient::MSG_SERVICE, gxsidA, gxsidB, + reinterpret_cast(ciao.data()), + ciao.size()); + } + else if(idService.isOwnId(gxsidB)) + { + std::string ciao("CiBone!"); + sendMail( GxsMailsClient::MSG_SERVICE, gxsidB, gxsidA, + reinterpret_cast(ciao.data()), + ciao.size()); + } } -#endif GxsTokenQueue::checkRequests(); } @@ -138,20 +302,19 @@ void p3GxsMails::notifyChanges(std::vector& changes) if (grpChange) { - typedef std::list::const_iterator itT; - for( itT it = grpChange->mGrpIdList.begin(); - it != grpChange->mGrpIdList.end(); ++it ) - { - const RsGxsGroupId& grpId = *it; - std::cout << "p3GxsMails::notifyChanges(...) got group " - << grpId << std::endl; - supersedePreferredGroup(grpId); - } + std::cout << "p3GxsMails::notifyChanges(...) grpChange" << std::endl; + requestGroupsData(&(grpChange->mGrpIdList)); } else if(msgChange) { - typedef std::map > mT; - for( mT::const_iterator it = msgChange->msgChangeMap.begin(); + std::cout << "p3GxsMails::notifyChanges(...) msgChange" << std::endl; + uint32_t token; + RsTokReqOptions opts; opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA; + getTokenService()->requestMsgInfo( token, 0xcaca, + opts, msgChange->msgChangeMap ); + GxsTokenQueue::queueRequest(token, MAILS_UPDATE); + + for( GxsMsgReq::const_iterator it = msgChange->msgChangeMap.begin(); it != msgChange->msgChangeMap.end(); ++it ) { const RsGxsGroupId& grpId = it->first; @@ -161,20 +324,22 @@ void p3GxsMails::notifyChanges(std::vector& changes) { const RsGxsMessageId& msgId = *vit; std::cout << "p3GxsMails::notifyChanges(...) got " - << "new message " << msgId << " in group " - << grpId << std::endl; + << "notification for message " << msgId + << " in group " << grpId << std::endl; } } } } } -bool p3GxsMails::requestGroupsList() +bool p3GxsMails::requestGroupsData(const std::list* groupIds) { - // std::cout << "p3GxsMails::requestGroupsList() GXS_REQUEST_TYPE_GROUP_META" << std::endl; + // std::cout << "p3GxsMails::requestGroupsList()" << std::endl; uint32_t token; RsTokReqOptions opts; opts.mReqType = GXS_REQUEST_TYPE_GROUP_DATA; - RsGenExchange::getTokenService()->requestGroupInfo(token, 0xcaca, opts); + if(!groupIds) getTokenService()->requestGroupInfo(token, 0xcaca, opts); + else getTokenService()->requestGroupInfo(token, 0xcaca, opts, *groupIds); GxsTokenQueue::queueRequest(token, GROUPS_LIST); return true; } + diff --git a/libretroshare/src/services/p3gxsmails.h b/libretroshare/src/services/p3gxsmails.h index 0a87d1575..197f5f5b3 100644 --- a/libretroshare/src/services/p3gxsmails.h +++ b/libretroshare/src/services/p3gxsmails.h @@ -24,21 +24,81 @@ #include "serialiser/rsgxsmailitems.h" // For RS_SERVICE_TYPE_GXS_MAIL #include "services/p3idservice.h" // For p3IdService +struct p3GxsMails; -class p3GxsMails : public RsGenExchange, public GxsTokenQueue +struct GxsMailsClient +{ + /// Subservices identifiers (like port for TCP) + enum GxsMailSubServices { MSG_SERVICE }; + + /** + * This is usually used to save a pointer to the p3GxsMails service (e.g. by + * coping it in a member variable), so as to be able to send mails, and to + * register as a mail receiver via + * p3GxsMails::registerGxsMailsClient(GxsMailSubServices, GxsMailsClient) + */ + //virtual void connectToGxsMails(p3GxsMails *pt) = 0 ; + + /** + * This will be called by p3GxsMails to dispatch mails to the subservice + * @param destinationId + * @param signingKey + * @param data + * @param dataSize + * @return true if dispatching goes fine, false otherwise + */ + virtual bool receiveGxsMail( const RsGxsId& destinationId, + const RsGxsId& signingKey, + uint8_t* data, uint32_t dataSize ) = 0; +}; + +struct p3GxsMails : RsGenExchange, GxsTokenQueue { -public: p3GxsMails( RsGeneralDataService* gds, RsNetworkExchangeService* nes, - p3IdService *identities ) : + p3IdService& identities ) : RsGenExchange( gds, nes, new RsGxsMailSerializer(), - RS_SERVICE_TYPE_GXS_MAIL, identities, + RS_SERVICE_TYPE_GXS_MAIL, &identities, AuthenPolicy(), RS_GXS_DEFAULT_MSG_STORE_PERIOD ), // TODO: Discuss with Cyril about this - GxsTokenQueue(this) {} + GxsTokenQueue(this), idService(identities) {} - /// Public interface - bool sendEmail( const RsGxsId& own_gxsid, const RsGxsId& recipient, - const std::string& body ); + /** + * Send an email to recipient, in the process author of the email is + * disclosed to the network (because the sent GXS item is signed), while + * recipient is not @see RsGxsMailBaseItem::recipientsHint for details on + * recipient protection. + * This method is part of the public interface of this service. + * @return true if the mail will be sent, false if not + */ + bool sendMail( GxsMailsClient::GxsMailSubServices service, + const RsGxsId& own_gxsid, const RsGxsId& recipient, + const uint8_t* data, uint32_t size, + RsGxsMailBaseItem::EncryptionMode cm = RsGxsMailBaseItem::RSA + ); + + /** + * Send an email to recipients, in the process author of the email is + * disclosed to the network (because the sent GXS item is signed), while + * recipients are not @see RsGxsMailBaseItem::recipientsHint for details on + * recipient protection. + * This method is part of the public interface of this service. + * @return true if the mail will be sent, false if not + */ + bool sendMail( GxsMailsClient::GxsMailSubServices service, + const RsGxsId& own_gxsid, + const std::vector& recipients, + const uint8_t* data, uint32_t size, + RsGxsMailBaseItem::EncryptionMode cm = RsGxsMailBaseItem::RSA + ); + + /** + * Register a client service to p3GxsMails to receive mails via + * GxsMailsClient::receiveGxsMail(...) callback + * This is NOT thread safe! + */ + void registerGxsMailsClient( GxsMailsClient::GxsMailSubServices serviceType, + GxsMailsClient* service ) + { servClients[serviceType] = service; } /** * @see GxsTokenQueue::handleResponse(uint32_t token, uint32_t req_type) @@ -59,17 +119,26 @@ protected: void notifyChanges(std::vector &changes); private: + /// Time interval of inactivity before a distribution group is unsubscribed + const static int32_t UNUSED_GROUP_UNSUBSCRIBE_INTERVAL = 0x76A700; // 3 months approx /// @brief AuthenPolicy check nothing ATM TODO talk with Cyril how this should be static uint32_t AuthenPolicy() { return 0; } /// Types to mark GXS queries and answhers - enum GxsReqResTypes { GROUPS_LIST, GROUP_CREATE }; + enum GxsReqResTypes { GROUPS_LIST, GROUP_CREATE, MAILS_UPDATE }; + /// Store the id of the preferred GXS group to send emails RsGxsGroupId preferredGroupId; + /// Used for items {de,en}cryption + p3IdService& idService; + + /// Stores pointers to client services to notify them about new mails + std::map servClients; + /// Request groups list to GXS backend. Async method. - bool requestGroupsList(); + bool requestGroupsData(const std::list* groupIds = NULL); /** * Check if current preferredGroupId is the best against potentialGrId, if @@ -84,21 +153,16 @@ private: //std::cout << "supersedePreferredGroup(const RsGxsGroupId& potentialGrId) " << preferredGroupId << " & encrypt_ids, + bool force_load, uint32_t& error_status ) +{ + std::set keyNotYetFoundIds; + + for( std::set::const_iterator it = encrypt_ids.begin(); + it != encrypt_ids.end(); ++it ) + { + const RsGxsId& gId(*it); + if(gId.isNull()) + { + std::cerr << "p3IdService::encryptData(...) (EE) got null GXS id" + << std::endl; + return false; + } + else keyNotYetFoundIds.insert(&gId); + } + + if(keyNotYetFoundIds.empty()) + { + std::cerr << "p3IdService::encryptData(...) (EE) got empty GXS ids set" + << std::endl; + print_stacktrace(); + return false; + } + + std::vector encryption_keys; + int maxRounds = force_load ? 6 : 1; + for( int i=0; i < maxRounds; ++i ) + { + for( std::set::iterator it = keyNotYetFoundIds.begin(); + it !=keyNotYetFoundIds.end(); ++it ) + { + RsTlvPublicRSAKey encryption_key; + if(getKey(**it, encryption_key) && !encryption_key.keyId.isNull()) + { + encryption_keys.push_back(encryption_key); + keyNotYetFoundIds.erase(it); + } + } + + if(keyNotYetFoundIds.empty()) break; + else usleep(500*1000); + } + + if(!keyNotYetFoundIds.empty()) + { + std::cerr << "p3IdService::encryptData(...) (EE) Cannot get " + << "encryption key for: "; + for( std::set::iterator it = keyNotYetFoundIds.begin(); + it !=keyNotYetFoundIds.end(); ++it ) + std::cerr << **it << " "; + std::cerr << std::endl; + print_stacktrace(); + + error_status = RS_GIXS_ERROR_KEY_NOT_AVAILABLE; + return false; + } + + if(!GxsSecurity::encrypt( encrypted_data, encrypted_data_size, + decrypted_data, decrypted_data_size, + encryption_keys )) + { + std::cerr << "p3IdService::encryptData(...) (EE) Encryption failed." + << std::endl; + print_stacktrace(); + + error_status = RS_GIXS_ERROR_UNKNOWN; + return false ; + } + + for( std::set::const_iterator it = encrypt_ids.begin(); + it != encrypt_ids.end(); ++it ) + { + timeStampKey( *it, + RsIdentityUsage( + serviceType(), + RsIdentityUsage::IDENTITY_GENERIC_ENCRYPTION ) ); + } + + error_status = RS_GIXS_ERROR_NO_ERROR; + return true; +} + bool p3IdService::decryptData(const uint8_t *encrypted_data,uint32_t encrypted_data_size,uint8_t *& decrypted_data,uint32_t& decrypted_size,const RsGxsId& key_id,uint32_t& error_status) { RsTlvPrivateRSAKey encryption_key ; diff --git a/libretroshare/src/services/p3idservice.h b/libretroshare/src/services/p3idservice.h index addff0d1b..1f95fa241 100644 --- a/libretroshare/src/services/p3idservice.h +++ b/libretroshare/src/services/p3idservice.h @@ -287,11 +287,37 @@ public: virtual bool isOwnId(const RsGxsId& key_id) ; - virtual bool signData(const uint8_t *data,uint32_t data_size,const RsGxsId& signer_id,RsTlvKeySignature& signature,uint32_t& signing_error) ; - virtual bool validateData(const uint8_t *data, uint32_t data_size, const RsTlvKeySignature& signature, bool force_load, const RsIdentityUsage &info, uint32_t& signing_error) ; + virtual bool signData( const uint8_t* data, + uint32_t data_size, + const RsGxsId& signer_id, + RsTlvKeySignature& signature, + uint32_t& signing_error); - virtual bool encryptData(const uint8_t *decrypted_data,uint32_t decrypted_data_size,uint8_t *& encrypted_data,uint32_t& encrypted_data_size,const RsGxsId& encryption_key_id,bool force_load,uint32_t& encryption_error) ; - virtual bool decryptData(const uint8_t *encrypted_data,uint32_t encrypted_data_size,uint8_t *& decrypted_data,uint32_t& decrypted_data_size,const RsGxsId& encryption_key_id,uint32_t& encryption_error) ; + virtual bool validateData( const uint8_t *data, uint32_t data_size, + const RsTlvKeySignature& signature, + bool force_load, const RsIdentityUsage &info, + uint32_t& signing_error ); + + virtual bool encryptData( const uint8_t* decrypted_data, + uint32_t decrypted_data_size, + uint8_t*& encrypted_data, + uint32_t& encrypted_data_size, + const RsGxsId& encryption_key_id, + bool force_load, uint32_t& encryption_error); + + bool encryptData( const uint8_t* decrypted_data, + uint32_t decrypted_data_size, + uint8_t*& encrypted_data, + uint32_t& encrypted_data_size, + const std::set& encrypt_ids, + bool force_load, uint32_t& error_status ); + + virtual bool decryptData( const uint8_t* encrypted_data, + uint32_t encrypted_data_size, + uint8_t*& decrypted_data, + uint32_t& decrypted_data_size, + const RsGxsId& encryption_key_id, + uint32_t& encryption_error ); virtual bool haveKey(const RsGxsId &id); virtual bool havePrivateKey(const RsGxsId &id); @@ -299,7 +325,9 @@ public: virtual bool getKey(const RsGxsId &id, RsTlvPublicRSAKey &key); virtual bool getPrivateKey(const RsGxsId &id, RsTlvPrivateRSAKey &key); - virtual bool requestKey(const RsGxsId &id, const std::list &peers, const RsIdentityUsage &use_info); + virtual bool requestKey( const RsGxsId &id, + const std::list &peers, + const RsIdentityUsage &use_info ); virtual bool requestPrivateKey(const RsGxsId &id); From 1f1f4ded02c5a3d4a272813e521b157e478ef74d Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Tue, 31 Jan 2017 20:14:17 +0100 Subject: [PATCH 06/35] GxsMail: Implemented RSA mail receiving RsGxsMailBaseItem::deserialize(...) fix offset calculation RsGxsMailItem::serialize(...) fix offset calculation RsGxsMailBaseItem initialize cryptoType to UNDEFINED_ENCRYPTION p3IdService::decryptData(...) implemented multi id variant RsGixs::*cryptData(...) proper param order p3IdService::*cryptData(...) proper param order --- libretroshare/src/grouter/p3grouter.cc | 8 +- libretroshare/src/gxs/rsgixs.h | 15 ++- .../src/serialiser/rsgxsmailitems.cc | 6 +- libretroshare/src/serialiser/rsgxsmailitems.h | 19 ++- libretroshare/src/services/p3gxsmails.cpp | 104 +++++++++++++-- libretroshare/src/services/p3gxsmails.h | 9 +- libretroshare/src/services/p3idservice.cc | 125 ++++++++++++++++-- libretroshare/src/services/p3idservice.h | 19 ++- 8 files changed, 260 insertions(+), 45 deletions(-) diff --git a/libretroshare/src/grouter/p3grouter.cc b/libretroshare/src/grouter/p3grouter.cc index 5f2b6e7d0..1ba453d1b 100644 --- a/libretroshare/src/grouter/p3grouter.cc +++ b/libretroshare/src/grouter/p3grouter.cc @@ -1892,7 +1892,9 @@ bool p3GRouter::encryptDataItem(RsGRouterGenericDataItem *item,const RsGxsId& de uint32_t encrypted_size =0; uint32_t error_status ; - if(!mGixs->encryptData(item->data_bytes,item->data_size,encrypted_data,encrypted_size,destination_key,true,error_status)) + if(!mGixs->encryptData( item->data_bytes, item->data_size, encrypted_data, + encrypted_size, destination_key, error_status, + true )) { std::cerr << "(EE) Cannot encrypt: " ; if(error_status == RsGixs::RS_GIXS_ERROR_KEY_NOT_AVAILABLE) std::cerr << " key not available for ID = " << destination_key << std::endl; @@ -1926,7 +1928,9 @@ bool p3GRouter::decryptDataItem(RsGRouterGenericDataItem *item) uint32_t decrypted_size =0; uint32_t error_status ; - if(!mGixs->decryptData(item->data_bytes,item->data_size,decrypted_data,decrypted_size,item->destination_key,error_status)) + if(!mGixs->decryptData( item->data_bytes, item->data_size, decrypted_data, + decrypted_size, item->destination_key, error_status, + true )) { if(error_status == RsGixs::RS_GIXS_ERROR_KEY_NOT_AVAILABLE) std::cerr << "(EE) Cannot decrypt incoming message. Key " << item->destination_key << " unknown." << std::endl; diff --git a/libretroshare/src/gxs/rsgixs.h b/libretroshare/src/gxs/rsgixs.h index 2f2c0f0ec..6e8591a4a 100644 --- a/libretroshare/src/gxs/rsgixs.h +++ b/libretroshare/src/gxs/rsgixs.h @@ -103,7 +103,7 @@ typedef PGPIdType RsPgpId; class RsGixs { public: - + // TODO: cleanup this should be an enum! static const uint32_t RS_GIXS_ERROR_NO_ERROR = 0x0000 ; static const uint32_t RS_GIXS_ERROR_UNKNOWN = 0x0001 ; static const uint32_t RS_GIXS_ERROR_KEY_NOT_AVAILABLE = 0x0002 ; @@ -119,8 +119,17 @@ public: virtual bool signData(const uint8_t *data,uint32_t data_size,const RsGxsId& signer_id,RsTlvKeySignature& signature,uint32_t& signing_error) = 0 ; virtual bool validateData(const uint8_t *data,uint32_t data_size,const RsTlvKeySignature& signature,bool force_load,const RsIdentityUsage& info,uint32_t& signing_error) = 0 ; - virtual bool encryptData(const uint8_t *clear_data,uint32_t clear_data_size,uint8_t *& encrypted_data,uint32_t& encrypted_data_size,const RsGxsId& encryption_key_id,bool force_load,uint32_t& encryption_error) = 0 ; - virtual bool decryptData(const uint8_t *encrypted_data,uint32_t encrypted_data_size,uint8_t *& clear_data,uint32_t& clear_data_size,const RsGxsId& encryption_key_id,uint32_t& encryption_error) = 0 ; + virtual bool encryptData( const uint8_t *clear_data, + uint32_t clear_data_size, + uint8_t *& encrypted_data, + uint32_t& encrypted_data_size, + const RsGxsId& encryption_key_id, + uint32_t& encryption_error, bool force_load) = 0 ; + virtual bool decryptData( const uint8_t *encrypted_data, + uint32_t encrypted_data_size, + uint8_t *& clear_data, uint32_t& clear_data_size, + const RsGxsId& encryption_key_id, + uint32_t& encryption_error, bool force_load) = 0 ; virtual bool getOwnIds(std::list& ids) = 0; virtual bool isOwnId(const RsGxsId& key_id) = 0 ; diff --git a/libretroshare/src/serialiser/rsgxsmailitems.cc b/libretroshare/src/serialiser/rsgxsmailitems.cc index a3d624b44..40d71b220 100644 --- a/libretroshare/src/serialiser/rsgxsmailitems.cc +++ b/libretroshare/src/serialiser/rsgxsmailitems.cc @@ -25,7 +25,7 @@ bool RsGxsMailBaseItem::serialize(uint8_t* data, uint32_t size, uint32_t& offset) const { bool ok = setRsItemHeader(data, size, PacketId(), size); - ok = ok && (offset += 8); // Take in account the header + ok = ok && (offset += 8); // Take header in account ok = ok && setRawUInt8(data, size, &offset, cryptoType); ok = ok && recipientsHint.serialise(data, size, offset); return ok; @@ -36,10 +36,10 @@ bool RsGxsMailBaseItem::deserialize(const uint8_t* data, uint32_t& size, { void* dataPtr = reinterpret_cast(const_cast(data)); uint32_t rssize = getRsItemSize(dataPtr); - uint32_t roffset = offset + 8; + uint32_t roffset = offset + 8; // Take header in account bool ok = rssize <= size; uint8_t crType; - ok = ok && getRawUInt8(dataPtr, rssize, &offset, &crType); + ok = ok && getRawUInt8(dataPtr, rssize, &roffset, &crType); cryptoType = static_cast(crType); ok = ok && recipientsHint.deserialise(dataPtr, rssize, roffset); if(ok) { size = rssize; offset = roffset; } diff --git a/libretroshare/src/serialiser/rsgxsmailitems.h b/libretroshare/src/serialiser/rsgxsmailitems.h index f57439f43..278b18c48 100644 --- a/libretroshare/src/serialiser/rsgxsmailitems.h +++ b/libretroshare/src/serialiser/rsgxsmailitems.h @@ -38,7 +38,8 @@ struct RsGxsMailBaseItem : RsGxsMsgItem { RsGxsMailBaseItem(GxsMailItemsSubtypes subtype) : RsGxsMsgItem( RS_SERVICE_TYPE_GXS_MAIL, - static_cast(subtype) ) {} + static_cast(subtype) ), + cryptoType(UNDEFINED_ENCRYPTION) {} /// Values must fit into uint8_t enum EncryptionMode @@ -86,11 +87,10 @@ struct RsGxsMailBaseItem : RsGxsMsgItem */ RsGxsId recipientsHint; - void inline saltRecipientHint(const RsGxsId& salt) - { saltRecipientHint(recipientsHint, salt); } - void static inline saltRecipientHint(RsGxsId& hint, const RsGxsId& salt) { hint = hint | salt; } + void inline saltRecipientHint(const RsGxsId& salt) + { saltRecipientHint(recipientsHint, salt); } /** * @brief maybeRecipient given an id and an hint check if they match @@ -102,6 +102,8 @@ struct RsGxsMailBaseItem : RsGxsMsgItem */ bool static inline maybeRecipient(const RsGxsId& hint, const RsGxsId& id) { return (~id|hint) == allRecipientsHint; } + bool inline maybeRecipient(const RsGxsId& id) const + { return maybeRecipient(recipientsHint, id); } const static RsGxsId allRecipientsHint; @@ -137,9 +139,12 @@ struct RsGxsMailItem : RsGxsMailBaseItem uint32_t size() const { return RsGxsMailBaseItem::size() + payload.size(); } bool serialize(uint8_t* data, uint32_t size, uint32_t& offset) const { - return size < MAX_SIZE - && RsGxsMailBaseItem::serialize(data, size, offset) - && memcpy(data+offset, &payload[0], payload.size()); + bool ok = size < MAX_SIZE; + ok = ok && RsGxsMailBaseItem::serialize(data, size, offset); + uint32_t psz = payload.size(); + ok = ok && memcpy(data+offset, &payload[0], psz); + offset += psz; + return ok; } bool deserialize(const uint8_t* data, uint32_t& size, uint32_t& offset) { diff --git a/libretroshare/src/services/p3gxsmails.cpp b/libretroshare/src/services/p3gxsmails.cpp index 63a07f4d3..6083fbc9b 100644 --- a/libretroshare/src/services/p3gxsmails.cpp +++ b/libretroshare/src/services/p3gxsmails.cpp @@ -82,15 +82,15 @@ bool p3GxsMails::sendMail( GxsMailsClient::GxsMailSubServices service, // Public metadata item->meta.mAuthorId = own_gxsid; item->meta.mGroupId = preferredGroupId; + item->cryptoType = cm; typedef std::set::const_iterator siT; for(siT it = rcps.begin(); it != rcps.end(); ++it) - item->saltRecipientHint(*it); + item->saltRecipientHint(*it); // If there is jut one recipient salt with a random id to avoid leaking it if(rcps.size() == 1) item->saltRecipientHint(RsGxsId::random()); - /* At this point we do a lot of memory copying, it doesn't look pretty but * ATM haven't thinked of an elegant way to have the GxsMailSubServices * travelling encrypted withuot copying memory around or responsabilize the @@ -100,7 +100,7 @@ bool p3GxsMails::sendMail( GxsMailsClient::GxsMailSubServices service, uint32_t clearTextPldSize = size+2; item->payload.resize(clearTextPldSize); uint32_t _discard = 0; - setRawUInt16(&item->payload[0], clearTextPldSize, &_discard, serv); + setRawUInt16(&item->payload[0], 2, &_discard, serv); memcpy(&item->payload[2], data, size); switch (cm) @@ -119,7 +119,7 @@ bool p3GxsMails::sendMail( GxsMailsClient::GxsMailSubServices service, uint32_t encryptError = 0; if( idService.encryptData( &item->payload[0], clearTextPldSize, encryptedData, encryptedSize, - rcps, true, encryptError ) ) + rcps, encryptError, true ) ) { item->payload.resize(encryptedSize); memcpy(&item->payload[0], encryptedData, encryptedSize); @@ -143,6 +143,8 @@ bool p3GxsMails::sendMail( GxsMailsClient::GxsMailSubServices service, } uint32_t token; + std::cout << "p3GxsMails::sendEmail(...) sending mail to:"<< *recipients[0] + << " payload size: : " << item->payload.size() << std::endl; publishMsg(token, item); return true; } @@ -228,14 +230,89 @@ void p3GxsMails::handleResponse(uint32_t token, uint32_t req_type) case GXS_MAIL_SUBTYPE_MAIL: { RsGxsMailItem* msg = dynamic_cast(it); - if(msg) + if(!msg) + { + std::cerr << "p3GxsMails::handleResponse(...) " + << "GXS_MAIL_SUBTYPE_MAIL cast error, " + << "something really wrong is happening" + << std::endl; + break; + } + + + std::cout << "p3GxsMails::handleResponse(...) " + << "GXS_MAIL_SUBTYPE_MAIL got from: " + << msg->meta.mAuthorId + << " recipientsHint: " + << msg->recipientsHint << " cryptoType: " + << (uint32_t)msg->cryptoType + << " payload size: " << msg->payload.size() + << std::endl; + + std::set decryptIds; + std::list ownIds; + idService.getOwnIds(ownIds); + for(auto it = ownIds.begin(); it != ownIds.end(); ++it) + if(msg->maybeRecipient(*it)) decryptIds.insert(*it); + + if(decryptIds.empty()) { std::cout << "p3GxsMails::handleResponse(...) " - << "GXS_MAIL_SUBTYPE_MAIL got recipientsHint: " - << msg->recipientsHint << " cryptoType: " - << (uint32_t)msg->cryptoType - << " payload size: " << msg->payload.size() - << std::endl; + << "GXS_MAIL_SUBTYPE_MAIL hint match none" + << " of our own ids" << msg->recipientsHint + << std::endl; + + break; + } + + std::cout << "p3GxsMails::handleResponse(...) " + << "GXS_MAIL_SUBTYPE_MAIL hint: " + << msg->recipientsHint + << " match with own ids: "; + for(auto it=decryptIds.begin(); it != decryptIds.end(); ++it) + std::cout << *it; + std::cout << std::endl; + + switch (msg->cryptoType) + { + case RsGxsMailBaseItem::CLEAR_TEXT: + { + uint16_t csri = 0; + uint32_t off; + getRawUInt16(&msg->payload[0], 2, &off, &csri); + std::string str(reinterpret_cast(&msg->payload[2]), msg->payload.size()-2); + std::cout << "service: " << csri + << " got CLEAR_TEXT message: " + << str << std::endl; + break; + } + case RsGxsMailBaseItem::RSA: + { + uint8_t* decrypted_data = NULL; + uint32_t decrypted_data_size = 0; + uint32_t decryption_error; + if( idService.decryptData( + &msg->payload[0], + msg->payload.size(), decrypted_data, + decrypted_data_size, decryptIds, + decryption_error ) ) + { + uint16_t csri = *reinterpret_cast(decrypted_data); + std::string str(reinterpret_cast(decrypted_data+2), decrypted_data_size-2); + std::cout << "service: " << csri + << " got RSA message: " + << str << std::endl; + } + else std::cout << "p3GxsMails::handleResponse(...) " + << "GXS_MAIL_SUBTYPE_MAIL RSA decryption" + << " failed" << std::endl; + free(decrypted_data); + break; + } + default: + std::cout << "Unknown encryption type:" + << msg->cryptoType << std::endl; + break; } break; } @@ -247,6 +324,7 @@ void p3GxsMails::handleResponse(uint32_t token, uint32_t req_type) } } } + break; } default: std::cerr << "p3GxsMails::handleResponse(...) Unknown req_type: " @@ -271,14 +349,14 @@ void p3GxsMails::service_tick() std::string ciao("CiAone!"); sendMail( GxsMailsClient::MSG_SERVICE, gxsidA, gxsidB, reinterpret_cast(ciao.data()), - ciao.size()); + ciao.size(), RsGxsMailBaseItem::RSA ); } else if(idService.isOwnId(gxsidB)) { - std::string ciao("CiBone!"); + std::string ciao("CiBuono!"); sendMail( GxsMailsClient::MSG_SERVICE, gxsidB, gxsidA, reinterpret_cast(ciao.data()), - ciao.size()); + ciao.size(), RsGxsMailBaseItem::RSA ); } } diff --git a/libretroshare/src/services/p3gxsmails.h b/libretroshare/src/services/p3gxsmails.h index 197f5f5b3..cf05f7aae 100644 --- a/libretroshare/src/services/p3gxsmails.h +++ b/libretroshare/src/services/p3gxsmails.h @@ -125,8 +125,13 @@ private: /// @brief AuthenPolicy check nothing ATM TODO talk with Cyril how this should be static uint32_t AuthenPolicy() { return 0; } - /// Types to mark GXS queries and answhers - enum GxsReqResTypes { GROUPS_LIST, GROUP_CREATE, MAILS_UPDATE }; + /// Types to mark queries in tokens queue + enum GxsReqResTypes + { + GROUPS_LIST = 1, + GROUP_CREATE = 2, + MAILS_UPDATE = 3 + }; /// Store the id of the preferred GXS group to send emails RsGxsGroupId preferredGroupId; diff --git a/libretroshare/src/services/p3idservice.cc b/libretroshare/src/services/p3idservice.cc index 61722ebf8..022a92b6c 100644 --- a/libretroshare/src/services/p3idservice.cc +++ b/libretroshare/src/services/p3idservice.cc @@ -1036,7 +1036,13 @@ bool p3IdService::validateData(const uint8_t *data,uint32_t data_size,const RsTl return true ; } -bool p3IdService::encryptData(const uint8_t *decrypted_data,uint32_t decrypted_data_size,uint8_t *& encrypted_data,uint32_t& encrypted_data_size,const RsGxsId& encryption_key_id,bool force_load,uint32_t& error_status) +bool p3IdService::encryptData( const uint8_t *decrypted_data, + uint32_t decrypted_data_size, + uint8_t *& encrypted_data, + uint32_t& encrypted_data_size, + const RsGxsId& encryption_key_id, + uint32_t& error_status, + bool force_load ) { RsTlvPublicRSAKey encryption_key ; @@ -1071,7 +1077,7 @@ bool p3IdService::encryptData( const uint8_t* decrypted_data, uint8_t*& encrypted_data, uint32_t& encrypted_data_size, const std::set& encrypt_ids, - bool force_load, uint32_t& error_status ) + uint32_t& error_status, bool force_load ) { std::set keyNotYetFoundIds; @@ -1154,18 +1160,22 @@ bool p3IdService::encryptData( const uint8_t* decrypted_data, return true; } -bool p3IdService::decryptData(const uint8_t *encrypted_data,uint32_t encrypted_data_size,uint8_t *& decrypted_data,uint32_t& decrypted_size,const RsGxsId& key_id,uint32_t& error_status) +bool p3IdService::decryptData( const uint8_t *encrypted_data, + uint32_t encrypted_data_size, + uint8_t *& decrypted_data, + uint32_t& decrypted_size, + const RsGxsId& key_id, uint32_t& error_status, + bool force_load ) { RsTlvPrivateRSAKey encryption_key ; // Get the key, and let the cache find it. It's our own key, so we should be able to find it, even if it takes // some seconds. - for(int i=0;i<4;++i) - if(getPrivateKey(key_id,encryption_key)) - break ; - else - usleep(500*1000) ; // sleep half a sec. + int maxRounds = force_load ? 6 : 1; + for(int i=0; i& decrypt_ids, + uint32_t& error_status, + bool force_load ) +{ + std::set keyNotYetFoundIds; + + for( std::set::const_iterator it = decrypt_ids.begin(); + it != decrypt_ids.end(); ++it ) + { + const RsGxsId& gId(*it); + if(gId.isNull()) + { + std::cerr << "p3IdService::decryptData(...) (EE) got null GXS id" + << std::endl; + print_stacktrace(); + return false; + } + else keyNotYetFoundIds.insert(&gId); + } + + if(keyNotYetFoundIds.empty()) + { + std::cerr << "p3IdService::decryptData(...) (EE) got empty GXS ids set" + << std::endl; + print_stacktrace(); + return false; + } + + std::vector decryption_keys; + int maxRounds = force_load ? 6 : 1; + for( int i=0; i < maxRounds; ++i ) + { + for( std::set::iterator it = keyNotYetFoundIds.begin(); + it !=keyNotYetFoundIds.end(); ++it ) + { + RsTlvPrivateRSAKey decryption_key; + if( getPrivateKey(**it, decryption_key) + && !decryption_key.keyId.isNull() ) + { + decryption_keys.push_back(decryption_key); + keyNotYetFoundIds.erase(it); + } + } + + if(keyNotYetFoundIds.empty()) break; + else usleep(500*1000); + } + + if(!keyNotYetFoundIds.empty()) + { + std::cerr << "p3IdService::decryptData(...) (EE) Cannot get private key" + << " for: "; + for( std::set::iterator it = keyNotYetFoundIds.begin(); + it !=keyNotYetFoundIds.end(); ++it ) + std::cerr << **it << " "; + std::cerr << std::endl; + print_stacktrace(); + + error_status = RS_GIXS_ERROR_KEY_NOT_AVAILABLE; + return false; + } + + if(!GxsSecurity::decrypt( decrypted_data, decrypted_data_size, + encrypted_data, encrypted_data_size, + decryption_keys )) + { + std::cerr << "p3IdService::decryptData(...) (EE) Decryption failed." + << std::endl; + print_stacktrace(); + + error_status = RS_GIXS_ERROR_UNKNOWN; + return false ; + } + + for( std::set::const_iterator it = decrypt_ids.begin(); + it != decrypt_ids.end(); ++it ) + { + timeStampKey( *it, + RsIdentityUsage( + serviceType(), + RsIdentityUsage::IDENTITY_GENERIC_DECRYPTION ) ); + } + + error_status = RS_GIXS_ERROR_NO_ERROR; + return true; +} #ifdef TO_BE_REMOVED /********************************************************************************/ diff --git a/libretroshare/src/services/p3idservice.h b/libretroshare/src/services/p3idservice.h index 1f95fa241..c93581597 100644 --- a/libretroshare/src/services/p3idservice.h +++ b/libretroshare/src/services/p3idservice.h @@ -303,21 +303,32 @@ public: uint8_t*& encrypted_data, uint32_t& encrypted_data_size, const RsGxsId& encryption_key_id, - bool force_load, uint32_t& encryption_error); + uint32_t& error_status, + bool force_load = true ); bool encryptData( const uint8_t* decrypted_data, uint32_t decrypted_data_size, uint8_t*& encrypted_data, uint32_t& encrypted_data_size, const std::set& encrypt_ids, - bool force_load, uint32_t& error_status ); + uint32_t& error_status, bool force_loa = true ); virtual bool decryptData( const uint8_t* encrypted_data, uint32_t encrypted_data_size, uint8_t*& decrypted_data, uint32_t& decrypted_data_size, - const RsGxsId& encryption_key_id, - uint32_t& encryption_error ); + const RsGxsId& decryption_key_id, + uint32_t& error_status, + bool force_load = true ); + + virtual bool decryptData(const uint8_t* encrypted_data, + uint32_t encrypted_data_size, + uint8_t*& decrypted_data, + uint32_t& decrypted_data_size, + const std::set& decrypt_ids, + uint32_t& error_status, + bool force_load = true ); + virtual bool haveKey(const RsGxsId &id); virtual bool havePrivateKey(const RsGxsId &id); From 4daca00359a04c42ea6eb464961a8f468f3ad5ae Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Tue, 7 Feb 2017 20:33:06 +0100 Subject: [PATCH 07/35] More work on GXS mail subservices --- libretroshare/src/services/p3gxsmails.cpp | 173 ++++++++++++---------- libretroshare/src/services/p3gxsmails.h | 32 ++-- 2 files changed, 120 insertions(+), 85 deletions(-) diff --git a/libretroshare/src/services/p3gxsmails.cpp b/libretroshare/src/services/p3gxsmails.cpp index 6083fbc9b..0a8c8c457 100644 --- a/libretroshare/src/services/p3gxsmails.cpp +++ b/libretroshare/src/services/p3gxsmails.cpp @@ -149,6 +149,13 @@ bool p3GxsMails::sendMail( GxsMailsClient::GxsMailSubServices service, return true; } +void p3GxsMails::registerGxsMailsClient( + GxsMailsClient::GxsMailSubServices serviceType, GxsMailsClient* service) +{ + RS_STACK_MUTEX(servClientsMutex); + servClients[serviceType] = service; +} + void p3GxsMails::handleResponse(uint32_t token, uint32_t req_type) { @@ -239,81 +246,7 @@ void p3GxsMails::handleResponse(uint32_t token, uint32_t req_type) break; } - - std::cout << "p3GxsMails::handleResponse(...) " - << "GXS_MAIL_SUBTYPE_MAIL got from: " - << msg->meta.mAuthorId - << " recipientsHint: " - << msg->recipientsHint << " cryptoType: " - << (uint32_t)msg->cryptoType - << " payload size: " << msg->payload.size() - << std::endl; - - std::set decryptIds; - std::list ownIds; - idService.getOwnIds(ownIds); - for(auto it = ownIds.begin(); it != ownIds.end(); ++it) - if(msg->maybeRecipient(*it)) decryptIds.insert(*it); - - if(decryptIds.empty()) - { - std::cout << "p3GxsMails::handleResponse(...) " - << "GXS_MAIL_SUBTYPE_MAIL hint match none" - << " of our own ids" << msg->recipientsHint - << std::endl; - - break; - } - - std::cout << "p3GxsMails::handleResponse(...) " - << "GXS_MAIL_SUBTYPE_MAIL hint: " - << msg->recipientsHint - << " match with own ids: "; - for(auto it=decryptIds.begin(); it != decryptIds.end(); ++it) - std::cout << *it; - std::cout << std::endl; - - switch (msg->cryptoType) - { - case RsGxsMailBaseItem::CLEAR_TEXT: - { - uint16_t csri = 0; - uint32_t off; - getRawUInt16(&msg->payload[0], 2, &off, &csri); - std::string str(reinterpret_cast(&msg->payload[2]), msg->payload.size()-2); - std::cout << "service: " << csri - << " got CLEAR_TEXT message: " - << str << std::endl; - break; - } - case RsGxsMailBaseItem::RSA: - { - uint8_t* decrypted_data = NULL; - uint32_t decrypted_data_size = 0; - uint32_t decryption_error; - if( idService.decryptData( - &msg->payload[0], - msg->payload.size(), decrypted_data, - decrypted_data_size, decryptIds, - decryption_error ) ) - { - uint16_t csri = *reinterpret_cast(decrypted_data); - std::string str(reinterpret_cast(decrypted_data+2), decrypted_data_size-2); - std::cout << "service: " << csri - << " got RSA message: " - << str << std::endl; - } - else std::cout << "p3GxsMails::handleResponse(...) " - << "GXS_MAIL_SUBTYPE_MAIL RSA decryption" - << " failed" << std::endl; - free(decrypted_data); - break; - } - default: - std::cout << "Unknown encryption type:" - << msg->cryptoType << std::endl; - break; - } + handleEcryptedMail(msg); break; } default: @@ -421,3 +354,93 @@ bool p3GxsMails::requestGroupsData(const std::list* groupIds) return true; } +bool p3GxsMails::handleEcryptedMail(RsGxsMailItem* mail) +{ + std::set decryptIds; + std::list ownIds; + idService.getOwnIds(ownIds); + for(auto it = ownIds.begin(); it != ownIds.end(); ++it) + if(mail->maybeRecipient(*it)) decryptIds.insert(*it); + + // Hint match none of our own ids + if(decryptIds.empty()) goto hFail; + + for(auto it=decryptIds.begin(); it != decryptIds.end(); ++it) + std::cout << *it; + std::cout << std::endl; + + switch (mail->cryptoType) + { + case RsGxsMailBaseItem::CLEAR_TEXT: + { + uint16_t csri; + uint32_t off = 0; + getRawUInt16(&mail->payload[0], 2, &off, &csri); + std::cerr << "service: " << csri << " got CLEAR_TEXT mail!" + << std::endl; + if( !dispatchDecryptedMail( mail, &mail->payload[2], + mail->payload.size()-2 ) ) + goto hFail; + break; + } + case RsGxsMailBaseItem::RSA: + { + uint8_t* decrypted_data = NULL; + uint32_t decrypted_data_size = 0; + uint32_t decryption_error; + bool ok = idService.decryptData( &mail->payload[0], + mail->payload.size(), decrypted_data, + decrypted_data_size, decryptIds, + decryption_error ); + ok = ok && dispatchDecryptedMail( mail, decrypted_data, + decrypted_data_size ); + if(!ok) + { + std::cout << "p3GxsMails::handleEcryptedMail(...) " + << "RSA decryption failed" << std::endl; + free(decrypted_data); + goto hFail; + } + break; + } + default: + std::cout << "Unknown encryption type:" + << mail->cryptoType << std::endl; + goto hFail; + } + + return true; + +hFail: + delete mail; + return false; +} + +bool p3GxsMails::dispatchDecryptedMail( RsGxsMailItem* received_msg, + uint8_t* decrypted_data, + uint32_t decrypted_data_size ) +{ + uint16_t csri; + uint32_t off; + getRawUInt16(decrypted_data, decrypted_data_size, &off, &csri); + GxsMailsClient::GxsMailSubServices rsrvc; + rsrvc = static_cast(csri); + + GxsMailsClient* reecipientService = NULL; + { + RS_STACK_MUTEX(servClientsMutex); + reecipientService = servClients[rsrvc]; + } + if(reecipientService) + return reecipientService->receiveGxsMail( received_msg, + &decrypted_data[2], + decrypted_data_size-2 ); + else + { + std::cerr << "p3GxsMails::dispatchReceivedMail(...) " + << "got message for unknown service: " + << csri << std::endl; + return false; + } +} + diff --git a/libretroshare/src/services/p3gxsmails.h b/libretroshare/src/services/p3gxsmails.h index cf05f7aae..9d6f2e1d7 100644 --- a/libretroshare/src/services/p3gxsmails.h +++ b/libretroshare/src/services/p3gxsmails.h @@ -41,14 +41,16 @@ struct GxsMailsClient /** * This will be called by p3GxsMails to dispatch mails to the subservice - * @param destinationId - * @param signingKey - * @param data - * @param dataSize + * @param originalMessage message as received from GXS backend (encrypted) + * GxsMailsClient take ownership of it ( aka should take free/delete it + * when not needed anymore ) + * @param data buffer containing the decrypted data + * GxsMailsClient take ownership of it ( aka should take free/delete it + * when not needed anymore ) + * @param dataSize size of the buffer * @return true if dispatching goes fine, false otherwise */ - virtual bool receiveGxsMail( const RsGxsId& destinationId, - const RsGxsId& signingKey, + virtual bool receiveGxsMail( RsGxsMailItem* originalMessage, uint8_t* data, uint32_t dataSize ) = 0; }; @@ -60,7 +62,8 @@ struct p3GxsMails : RsGenExchange, GxsTokenQueue RS_SERVICE_TYPE_GXS_MAIL, &identities, AuthenPolicy(), RS_GXS_DEFAULT_MSG_STORE_PERIOD ), // TODO: Discuss with Cyril about this - GxsTokenQueue(this), idService(identities) {} + GxsTokenQueue(this), idService(identities), + servClientsMutex("p3GxsMails client services map mutex") {} /** * Send an email to recipient, in the process author of the email is @@ -94,11 +97,9 @@ struct p3GxsMails : RsGenExchange, GxsTokenQueue /** * Register a client service to p3GxsMails to receive mails via * GxsMailsClient::receiveGxsMail(...) callback - * This is NOT thread safe! */ void registerGxsMailsClient( GxsMailsClient::GxsMailSubServices serviceType, - GxsMailsClient* service ) - { servClients[serviceType] = service; } + GxsMailsClient* service ); /** * @see GxsTokenQueue::handleResponse(uint32_t token, uint32_t req_type) @@ -141,6 +142,8 @@ private: /// Stores pointers to client services to notify them about new mails std::map servClients; + RsMutex servClientsMutex; + /// Request groups list to GXS backend. Async method. bool requestGroupsData(const std::list* groupIds = NULL); @@ -169,5 +172,14 @@ private: /// @return true if has passed more then interval seconds time since timeStamp bool static inline olderThen(time_t timeStamp, int32_t interval) { return (timeStamp + interval) < time(NULL); } + + + /// Decrypt email content and pass it to dispatchDecryptedMail(...) + bool handleEcryptedMail(RsGxsMailItem* mail); + + /// Dispatch the message to the recipient service + bool dispatchDecryptedMail( RsGxsMailItem* received_msg, + uint8_t* decrypted_data, + uint32_t decrypted_data_size ); }; From 9cde0fd9964a5656e11fcd12b1b4fb28342831ee Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Thu, 9 Feb 2017 16:11:53 +0100 Subject: [PATCH 08/35] Put in place auth policy, storage time and testing Better memory handling for message dispatching Better typing for some methods --- libretroshare/src/rsserver/rsinit.cc | 2 + libretroshare/src/serialiser/rsbaseserial.cc | 3 +- libretroshare/src/serialiser/rsbaseserial.h | 3 +- libretroshare/src/services/p3gxsmails.cpp | 105 +++++++++++-------- libretroshare/src/services/p3gxsmails.h | 86 +++++++++------ 5 files changed, 121 insertions(+), 78 deletions(-) diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index 3eb9ba146..ea1b1b33f 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -1499,6 +1499,8 @@ int RsServer::StartupRetroShare() mGxsMails->setNetworkExchangeService(gxsmails_ns); pqih->addService(gxsmails_ns, true); mConfigMgr->addConfiguration("gxs_mail.cfg", gxsmails_ns); + + new TestGxsMailClientService(*mGxsMails); # endif // RS_GXS_MAIL // remove pword from memory diff --git a/libretroshare/src/serialiser/rsbaseserial.cc b/libretroshare/src/serialiser/rsbaseserial.cc index 2ef67cd5b..f7869a229 100644 --- a/libretroshare/src/serialiser/rsbaseserial.cc +++ b/libretroshare/src/serialiser/rsbaseserial.cc @@ -71,7 +71,8 @@ bool setRawUInt8(void *data, uint32_t size, uint32_t *offset, uint8_t in) } /* UInt16 get/set */ -bool getRawUInt16(void *data, uint32_t size, uint32_t *offset, uint16_t *out) +bool getRawUInt16( const void *data, uint32_t size, uint32_t *offset, + uint16_t *out ) { /* first check there is space */ if (size < *offset + 2) diff --git a/libretroshare/src/serialiser/rsbaseserial.h b/libretroshare/src/serialiser/rsbaseserial.h index 25e0f57cc..d32b2694d 100644 --- a/libretroshare/src/serialiser/rsbaseserial.h +++ b/libretroshare/src/serialiser/rsbaseserial.h @@ -51,7 +51,8 @@ bool getRawUInt8(void *data, uint32_t size, uint32_t *offset, uint8_t *out); bool setRawUInt8(void *data, uint32_t size, uint32_t *offset, uint8_t in); -bool getRawUInt16(void *data, uint32_t size, uint32_t *offset, uint16_t *out); +bool getRawUInt16( const void* data, uint32_t size, uint32_t *offset, + uint16_t *out ); bool setRawUInt16(void *data, uint32_t size, uint32_t *offset, uint16_t in); bool getRawUInt32(void *data, uint32_t size, uint32_t *offset, uint32_t *out); diff --git a/libretroshare/src/services/p3gxsmails.cpp b/libretroshare/src/services/p3gxsmails.cpp index 0a8c8c457..21bfc4460 100644 --- a/libretroshare/src/services/p3gxsmails.cpp +++ b/libretroshare/src/services/p3gxsmails.cpp @@ -229,14 +229,14 @@ void p3GxsMails::handleResponse(uint32_t token, uint32_t req_type) vT& mv(gIt->second); for( vT::const_iterator mIt = mv.begin(); mIt != mv.end(); ++mIt ) { - RsGxsMsgItem* it = *mIt; + RsGxsMsgItem* gItem = *mIt; std::cout << "p3GxsMails::handleResponse(...) MAILS_UPDATE " - << (uint32_t)it->PacketSubType() << std::endl; - switch(it->PacketSubType()) + << (uint32_t)gItem->PacketSubType() << std::endl; + switch(gItem->PacketSubType()) { case GXS_MAIL_SUBTYPE_MAIL: { - RsGxsMailItem* msg = dynamic_cast(it); + RsGxsMailItem* msg = dynamic_cast(gItem); if(!msg) { std::cerr << "p3GxsMails::handleResponse(...) " @@ -252,9 +252,10 @@ void p3GxsMails::handleResponse(uint32_t token, uint32_t req_type) default: std::cerr << "p3GxsMails::handleResponse(...) MAILS_UPDATE " << "Unknown mail subtype : " - << it->PacketSubType() << std::endl; + << gItem->PacketSubType() << std::endl; break; } + delete gItem; } } break; @@ -280,14 +281,14 @@ void p3GxsMails::service_tick() if(idService.isOwnId(gxsidA)) { std::string ciao("CiAone!"); - sendMail( GxsMailsClient::MSG_SERVICE, gxsidA, gxsidB, + sendMail( GxsMailsClient::TEST_SERVICE, gxsidA, gxsidB, reinterpret_cast(ciao.data()), ciao.size(), RsGxsMailBaseItem::RSA ); } else if(idService.isOwnId(gxsidB)) { std::string ciao("CiBuono!"); - sendMail( GxsMailsClient::MSG_SERVICE, gxsidB, gxsidA, + sendMail( GxsMailsClient::TEST_SERVICE, gxsidB, gxsidA, reinterpret_cast(ciao.data()), ciao.size(), RsGxsMailBaseItem::RSA ); } @@ -343,6 +344,35 @@ void p3GxsMails::notifyChanges(std::vector& changes) } } +uint32_t p3GxsMails::AuthenPolicy() +{ + uint32_t policy = 0; + uint32_t flag = 0; + + // This ensure propagated message have valid author signature + flag = GXS_SERV::MSG_AUTHEN_ROOT_AUTHOR_SIGN | + GXS_SERV::MSG_AUTHEN_CHILD_AUTHOR_SIGN; + RsGenExchange::setAuthenPolicyFlag( flag, policy, + RsGenExchange::PUBLIC_GRP_BITS ); + + /* This ensure that in for restricted and private groups only authorized + * authors get the messages. Really not used ATM but don't hurts. */ + flag |= GXS_SERV::MSG_AUTHEN_ROOT_PUBLISH_SIGN | + GXS_SERV::MSG_AUTHEN_CHILD_PUBLISH_SIGN; + RsGenExchange::setAuthenPolicyFlag( flag, policy, + RsGenExchange::RESTRICTED_GRP_BITS ); + RsGenExchange::setAuthenPolicyFlag( flag, policy, + RsGenExchange::PRIVATE_GRP_BITS ); + + /* This seems never used RetroShare wide but we should investigate it + * more before considering this conclusive */ + flag = 0; + RsGenExchange::setAuthenPolicyFlag( flag, policy, + RsGenExchange::GRP_OPTION_BITS ); + + return policy; +} + bool p3GxsMails::requestGroupsData(const std::list* groupIds) { // std::cout << "p3GxsMails::requestGroupsList()" << std::endl; @@ -354,7 +384,7 @@ bool p3GxsMails::requestGroupsData(const std::list* groupIds) return true; } -bool p3GxsMails::handleEcryptedMail(RsGxsMailItem* mail) +bool p3GxsMails::handleEcryptedMail(const RsGxsMailItem* mail) { std::set decryptIds; std::list ownIds; @@ -363,66 +393,50 @@ bool p3GxsMails::handleEcryptedMail(RsGxsMailItem* mail) if(mail->maybeRecipient(*it)) decryptIds.insert(*it); // Hint match none of our own ids - if(decryptIds.empty()) goto hFail; - - for(auto it=decryptIds.begin(); it != decryptIds.end(); ++it) - std::cout << *it; - std::cout << std::endl; + if(decryptIds.empty()) return true; switch (mail->cryptoType) { case RsGxsMailBaseItem::CLEAR_TEXT: { - uint16_t csri; + uint16_t csri = 0; uint32_t off = 0; - getRawUInt16(&mail->payload[0], 2, &off, &csri); + getRawUInt16(&mail->payload[0], mail->payload.size(), &off, &csri); std::cerr << "service: " << csri << " got CLEAR_TEXT mail!" << std::endl; - if( !dispatchDecryptedMail( mail, &mail->payload[2], - mail->payload.size()-2 ) ) - goto hFail; - break; + return dispatchDecryptedMail( mail, &mail->payload[0], + mail->payload.size() ); } case RsGxsMailBaseItem::RSA: { uint8_t* decrypted_data = NULL; uint32_t decrypted_data_size = 0; uint32_t decryption_error; - bool ok = idService.decryptData( &mail->payload[0], - mail->payload.size(), decrypted_data, - decrypted_data_size, decryptIds, - decryption_error ); - ok = ok && dispatchDecryptedMail( mail, decrypted_data, - decrypted_data_size ); - if(!ok) - { - std::cout << "p3GxsMails::handleEcryptedMail(...) " - << "RSA decryption failed" << std::endl; - free(decrypted_data); - goto hFail; - } - break; + bool ok = true; + if( idService.decryptData( &mail->payload[0], + mail->payload.size(), decrypted_data, + decrypted_data_size, decryptIds, + decryption_error ) ) + ok = dispatchDecryptedMail( mail, decrypted_data, + decrypted_data_size ); + free(decrypted_data); + return ok; } default: std::cout << "Unknown encryption type:" << mail->cryptoType << std::endl; - goto hFail; + return false; } - - return true; - -hFail: - delete mail; - return false; } -bool p3GxsMails::dispatchDecryptedMail( RsGxsMailItem* received_msg, - uint8_t* decrypted_data, +bool p3GxsMails::dispatchDecryptedMail( const RsGxsMailItem* received_msg, + const uint8_t* decrypted_data, uint32_t decrypted_data_size ) { - uint16_t csri; - uint32_t off; - getRawUInt16(decrypted_data, decrypted_data_size, &off, &csri); + std::cout << "p3GxsMails::dispatchDecryptedMail(, , " << decrypted_data_size << ")" << std::endl; + uint16_t csri = 0; + uint32_t off = 0; + getRawUInt16( decrypted_data, decrypted_data_size, &off, &csri); GxsMailsClient::GxsMailSubServices rsrvc; rsrvc = static_cast(csri); @@ -431,6 +445,7 @@ bool p3GxsMails::dispatchDecryptedMail( RsGxsMailItem* received_msg, RS_STACK_MUTEX(servClientsMutex); reecipientService = servClients[rsrvc]; } + if(reecipientService) return reecipientService->receiveGxsMail( received_msg, &decrypted_data[2], diff --git a/libretroshare/src/services/p3gxsmails.h b/libretroshare/src/services/p3gxsmails.h index 9d6f2e1d7..110e8fe47 100644 --- a/libretroshare/src/services/p3gxsmails.h +++ b/libretroshare/src/services/p3gxsmails.h @@ -29,39 +29,27 @@ struct p3GxsMails; struct GxsMailsClient { /// Subservices identifiers (like port for TCP) - enum GxsMailSubServices { MSG_SERVICE }; - - /** - * This is usually used to save a pointer to the p3GxsMails service (e.g. by - * coping it in a member variable), so as to be able to send mails, and to - * register as a mail receiver via - * p3GxsMails::registerGxsMailsClient(GxsMailSubServices, GxsMailsClient) - */ - //virtual void connectToGxsMails(p3GxsMails *pt) = 0 ; + enum GxsMailSubServices { TEST_SERVICE = 1 }; /** * This will be called by p3GxsMails to dispatch mails to the subservice * @param originalMessage message as received from GXS backend (encrypted) - * GxsMailsClient take ownership of it ( aka should take free/delete it - * when not needed anymore ) * @param data buffer containing the decrypted data - * GxsMailsClient take ownership of it ( aka should take free/delete it - * when not needed anymore ) * @param dataSize size of the buffer * @return true if dispatching goes fine, false otherwise */ - virtual bool receiveGxsMail( RsGxsMailItem* originalMessage, - uint8_t* data, uint32_t dataSize ) = 0; + virtual bool receiveGxsMail( const RsGxsMailItem* originalMessage, + const uint8_t* data, uint32_t dataSize ) = 0; }; + struct p3GxsMails : RsGenExchange, GxsTokenQueue { p3GxsMails( RsGeneralDataService* gds, RsNetworkExchangeService* nes, p3IdService& identities ) : RsGenExchange( gds, nes, new RsGxsMailSerializer(), RS_SERVICE_TYPE_GXS_MAIL, &identities, - AuthenPolicy(), - RS_GXS_DEFAULT_MSG_STORE_PERIOD ), // TODO: Discuss with Cyril about this + AuthenPolicy(), GXS_STORAGE_PERIOD ), GxsTokenQueue(this), idService(identities), servClientsMutex("p3GxsMails client services map mutex") {} @@ -101,9 +89,8 @@ struct p3GxsMails : RsGenExchange, GxsTokenQueue void registerGxsMailsClient( GxsMailsClient::GxsMailSubServices serviceType, GxsMailsClient* service ); - /** - * @see GxsTokenQueue::handleResponse(uint32_t token, uint32_t req_type) - */ + + /// @see GxsTokenQueue::handleResponse(uint32_t token, uint32_t req_type) virtual void handleResponse(uint32_t token, uint32_t req_type); /// @see RsGenExchange::service_tick() @@ -120,11 +107,27 @@ protected: void notifyChanges(std::vector &changes); private: - /// Time interval of inactivity before a distribution group is unsubscribed - const static int32_t UNUSED_GROUP_UNSUBSCRIBE_INTERVAL = 0x76A700; // 3 months approx + /** Time interval of inactivity before a distribution group is unsubscribed. + * Approximatively 3 months seems ok ATM. */ + const static int32_t UNUSED_GROUP_UNSUBSCRIBE_INTERVAL = 0x76A700; - /// @brief AuthenPolicy check nothing ATM TODO talk with Cyril how this should be - static uint32_t AuthenPolicy() { return 0; } + /** + * This should be as little as possible as the size of the database can grow + * very fast taking in account we are handling mails for the whole network. + * We do prefer to resend a not acknowledged yet mail after + * GXS_STORAGE_PERIOD has passed and keep it little. + * Tought it can't be too little as this may cause signed acknowledged to + * get lost thus causing resend and fastly grow perceived async latency, in + * case two sporadically connected users sends mails each other. + * TODO: While it is ok for signed acknowledged to stays in the DB for a + * full GXS_STORAGE_PERIOD, mails should be removed as soon as a valid + * signed acknowledged is received for each of them. + * Two weeks seems fair ATM. + */ + const static uint32_t GXS_STORAGE_PERIOD = 0x127500; + + /// Define how the backend should handle authentication based on signatures + static uint32_t AuthenPolicy(); /// Types to mark queries in tokens queue enum GxsReqResTypes @@ -158,7 +161,6 @@ private: */ bool inline supersedePreferredGroup(const RsGxsGroupId& potentialGrId) { - //std::cout << "supersedePreferredGroup(const RsGxsGroupId& potentialGrId) " << preferredGroupId << " meta.mAuthorId << std::endl + << "\t" << std::string((char*)data, dataSize) << std::endl; + return true; + } +}; + From 55ff9067cf9736f1977539aed697f97c0cdfffe3 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Sat, 18 Feb 2017 20:32:25 +0100 Subject: [PATCH 09/35] Acknoweldge mail reception via presigned receipt This method does protect recipient metadata but doesn't support multicasting so if a mail has N recipients N copies of the mail need to be sent to the group RsGenExchange made some members protected instead of private so child classes can use them Create Rs{G,N}xsMailPresignedReceipt items to prepare and dispatch receipts Move RsNxsMsg deserialization to RsNxsMsg::deserialize(...) method --- libretroshare/src/gxs/rsgenexchange.h | 6 +- .../src/serialiser/rsgxsmailitems.cc | 17 +- libretroshare/src/serialiser/rsgxsmailitems.h | 86 ++++--- libretroshare/src/serialiser/rsnxsitems.cc | 43 +++- libretroshare/src/serialiser/rsnxsitems.h | 63 ++--- libretroshare/src/services/p3gxsmails.cpp | 228 ++++++++++++------ libretroshare/src/services/p3gxsmails.h | 18 +- 7 files changed, 281 insertions(+), 180 deletions(-) diff --git a/libretroshare/src/gxs/rsgenexchange.h b/libretroshare/src/gxs/rsgenexchange.h index f14619c45..b918789c7 100644 --- a/libretroshare/src/gxs/rsgenexchange.h +++ b/libretroshare/src/gxs/rsgenexchange.h @@ -718,18 +718,19 @@ private: */ uint8_t createGroup(RsNxsGrp* grp, RsTlvSecurityKeySet& keySet); +protected: /*! * This completes the creation of an instance on RsNxsMsg * by assigning it a groupId and signature via SHA1 and EVP_sign respectively * What signatures are calculated are based on the authentication policy * of the service * @param msg the Nxs message to create - * CREATE_FAIL, CREATE_SUCCESS, CREATE_ID_SIGN_NOT_AVAIL * @return CREATE_SUCCESS for success, CREATE_FAIL for fail, * CREATE_FAIL_TRY_LATER for Id sign key not avail (but requested) */ int createMessage(RsNxsMsg* msg); +private: /*! * convenience function to create sign * @param signSet signatures are stored here @@ -876,8 +877,7 @@ private: time_t mLastCheck; RsGxsIntegrityCheck* mIntegrityCheck; -private: - +protected: // TODO: cleanup this should be an enum! const uint8_t CREATE_FAIL, CREATE_SUCCESS, CREATE_FAIL_TRY_LATER, SIGN_MAX_WAITING_TIME; const uint8_t SIGN_FAIL, SIGN_SUCCESS, SIGN_FAIL_TRY_LATER; diff --git a/libretroshare/src/serialiser/rsgxsmailitems.cc b/libretroshare/src/serialiser/rsgxsmailitems.cc index 40d71b220..38cd90140 100644 --- a/libretroshare/src/serialiser/rsgxsmailitems.cc +++ b/libretroshare/src/serialiser/rsgxsmailitems.cc @@ -28,6 +28,7 @@ bool RsGxsMailBaseItem::serialize(uint8_t* data, uint32_t size, ok = ok && (offset += 8); // Take header in account ok = ok && setRawUInt8(data, size, &offset, cryptoType); ok = ok && recipientsHint.serialise(data, size, offset); + ok = ok && setRawUInt64(data, size, &offset, receiptId); return ok; } @@ -42,6 +43,7 @@ bool RsGxsMailBaseItem::deserialize(const uint8_t* data, uint32_t& size, ok = ok && getRawUInt8(dataPtr, rssize, &roffset, &crType); cryptoType = static_cast(crType); ok = ok && recipientsHint.deserialise(dataPtr, rssize, roffset); + ok = ok && getRawUInt64(dataPtr, rssize, &roffset, &receiptId); if(ok) { size = rssize; offset = roffset; } else size = 0; return ok; @@ -68,19 +70,19 @@ bool RsGxsMailSerializer::serialise(RsItem* item, void* data, uint32_t* size) { uint32_t offset = 0; RsGxsMailItem* i = dynamic_cast(item); - ok = ok && i->serialize(dataPtr, itemSize, offset); + ok = i->serialize(dataPtr, itemSize, offset); break; } - case GXS_MAIL_SUBTYPE_ACK: + case GXS_MAIL_SUBTYPE_RECEIPT: { - RsGxsMailAckItem* i = dynamic_cast(item); - ok = ok && setRsItemHeader(data, itemSize, item->PacketId(), itemSize); - uint32_t offset = 8; - ok = ok && i->recipient.serialise(data, itemSize, offset); + RsGxsMailPresignedReceipt* i = + dynamic_cast(item); + uint32_t offset = 0; + ok = i->serialize(dataPtr, itemSize, offset); break; } case GXS_MAIL_SUBTYPE_GROUP: - ok = ok && setRsItemHeader(data, itemSize, item->PacketId(), itemSize); + ok = setRsItemHeader(data, itemSize, item->PacketId(), itemSize); break; default: ok = false; break; } @@ -94,3 +96,4 @@ bool RsGxsMailSerializer::serialise(RsItem* item, void* data, uint32_t* size) std::cout << "RsGxsMailSerializer::serialise(...) failed!" << std::endl; return false; } + diff --git a/libretroshare/src/serialiser/rsgxsmailitems.h b/libretroshare/src/serialiser/rsgxsmailitems.h index 278b18c48..f215d10a2 100644 --- a/libretroshare/src/serialiser/rsgxsmailitems.h +++ b/libretroshare/src/serialiser/rsgxsmailitems.h @@ -30,16 +30,60 @@ enum GxsMailItemsSubtypes { GXS_MAIL_SUBTYPE_MAIL = 1, - GXS_MAIL_SUBTYPE_ACK = 2, + GXS_MAIL_SUBTYPE_RECEIPT = 2, GXS_MAIL_SUBTYPE_GROUP = 3 }; +struct RsNxsMailPresignedReceipt : RsNxsMsg +{ + RsNxsMailPresignedReceipt() : RsNxsMsg(RS_SERVICE_TYPE_GXS_MAIL) {} +}; + +struct RsGxsMailPresignedReceipt : RsGxsMsgItem +{ + RsGxsMailPresignedReceipt() : + RsGxsMsgItem( RS_SERVICE_TYPE_GXS_MAIL, + static_cast(GXS_MAIL_SUBTYPE_RECEIPT) ), + receiptId(0) {} + + uint64_t receiptId; + + static uint32_t inline size() + { + return 8 + // Header + 8; // receiptId + } + bool serialize(uint8_t* data, uint32_t size, uint32_t& offset) const + { + bool ok = setRsItemHeader(data, size, PacketId(), size); + ok = ok && (offset += 8); // Take header in account + ok = ok && setRawUInt64(data, size, &offset, receiptId); + return ok; + } + bool deserialize(const uint8_t* data, uint32_t& size, uint32_t& offset) + { + void* dataPtr = reinterpret_cast(const_cast(data)); + uint32_t rssize = getRsItemSize(dataPtr); + uint32_t roffset = offset + 8; // Take header in account + bool ok = rssize <= size; + ok = ok && getRawUInt64(dataPtr, rssize, &roffset, &receiptId); + if(ok) { size = rssize; offset = roffset; } + else size = 0; + return ok; + } + + void clear() { receiptId = 0; } + std::ostream &print(std::ostream &out, uint16_t /*indent = 0*/) + { return out << receiptId; } +}; + + struct RsGxsMailBaseItem : RsGxsMsgItem { RsGxsMailBaseItem(GxsMailItemsSubtypes subtype) : RsGxsMsgItem( RS_SERVICE_TYPE_GXS_MAIL, static_cast(subtype) ), - cryptoType(UNDEFINED_ENCRYPTION) {} + cryptoType(UNDEFINED_ENCRYPTION), receiptId(0) {} /// Values must fit into uint8_t enum EncryptionMode @@ -107,10 +151,13 @@ struct RsGxsMailBaseItem : RsGxsMsgItem const static RsGxsId allRecipientsHint; + uint64_t receiptId; + void inline clear() { cryptoType = UNDEFINED_ENCRYPTION; recipientsHint.clear(); + receiptId = 0; meta = RsMsgMetaData(); } @@ -118,7 +165,8 @@ struct RsGxsMailBaseItem : RsGxsMsgItem { return 8 + // Header 1 + // cryptoType - RsGxsId::serial_size(); // recipientsHint + RsGxsId::serial_size() + // recipientsHint + 8; // receiptId } bool serialize(uint8_t* data, uint32_t size, uint32_t& offset) const; bool deserialize(const uint8_t* data, uint32_t& size, uint32_t& offset); @@ -160,16 +208,6 @@ struct RsGxsMailItem : RsGxsMailBaseItem const static uint32_t MAX_SIZE = 10*8*1024*1024; }; -struct RsGxsMailAckItem : RsGxsMailBaseItem -{ - RsGxsMailAckItem() : RsGxsMailBaseItem(GXS_MAIL_SUBTYPE_ACK) {} - RsGxsId recipient; - - void clear() { recipient.clear(); } - std::ostream &print(std::ostream &out, uint16_t /*indent = 0*/) - { return out << recipient.toStdString(); } -}; - struct RsGxsMailGroupItem : RsGxsGrpItem { RsGxsMailGroupItem() : @@ -202,18 +240,8 @@ struct RsGxsMailSerializer : RsSerialType if(i) sz = i->size(); break; } - case GXS_MAIL_SUBTYPE_ACK: - { - RsGxsMailAckItem* i = dynamic_cast(item); - if(i) - { - sz = 8; // Header - sz += 4; // RsGxsMailBaseItem::recipient_hint - sz += 1; // RsGxsMailAckItem::read - sz += i->recipient.serial_size(); - } - break; - } + case GXS_MAIL_SUBTYPE_RECEIPT: + sz = RsGxsMailPresignedReceipt::size(); break; case GXS_MAIL_SUBTYPE_GROUP: sz = 8; break; default: break; } @@ -229,6 +257,7 @@ struct RsGxsMailSerializer : RsSerialType uint32_t rssize = getRsItemSize(data); uint8_t pktv = getRsItemVersion(rstype); uint16_t srvc = getRsItemService(rstype); + const uint8_t* dataPtr = reinterpret_cast(data); if ( (RS_PKT_VERSION_SERVICE != pktv) || // 0x02 (RS_SERVICE_TYPE_GXS_MAIL != srvc) || // 0x0230 = 560 @@ -248,16 +277,15 @@ struct RsGxsMailSerializer : RsSerialType { RsGxsMailItem* i = new RsGxsMailItem(); uint32_t offset = 0; - const uint8_t* dataPtr = reinterpret_cast(data); ok = ok && i->deserialize(dataPtr, *size, offset); ret = i; break; } - case GXS_MAIL_SUBTYPE_ACK: + case GXS_MAIL_SUBTYPE_RECEIPT: { - RsGxsMailAckItem* i = new RsGxsMailAckItem(); + RsGxsMailPresignedReceipt* i = new RsGxsMailPresignedReceipt(); uint32_t offset = 0; - ok &= i->recipient.deserialise(data, *size, offset); + ok &= i->deserialize(dataPtr, *size, offset); ret = i; break; } diff --git a/libretroshare/src/serialiser/rsnxsitems.cc b/libretroshare/src/serialiser/rsnxsitems.cc index d17002ca9..db7892c8a 100644 --- a/libretroshare/src/serialiser/rsnxsitems.cc +++ b/libretroshare/src/serialiser/rsnxsitems.cc @@ -199,6 +199,30 @@ bool RsNxsMsg::serialise(void *data, uint32_t& size) const return ok; } +bool RsNxsMsg::deserialize( const uint8_t* data, uint32_t& size, + uint32_t& offset ) +{ + void* dataPtr = reinterpret_cast(const_cast(data+offset)); + + uint32_t rssize = getRsItemSize(dataPtr); + uint32_t roffset = 8; // Take header in account + + bool ok = rssize+offset <= size; + ok = ok && getRawUInt32(dataPtr, rssize, &roffset, &transactionNumber); + ok = ok && getRawUInt8(dataPtr, rssize, &roffset, &pos); + ok = ok && msgId.deserialise(dataPtr, rssize, roffset); + ok = ok && grpId.deserialise(dataPtr, rssize, roffset); + ok = ok && msg.GetTlv(dataPtr, rssize, &roffset); + ok = ok && meta.GetTlv(dataPtr, rssize, &roffset); + + if(ok) { size = rssize; offset += roffset; } + else std::cerr << "RsNxsMsg::deserialize(, " << size << ", " << offset + << ") failed at: " << roffset << " rssize: " << rssize + << std::endl; + + return ok; +} + bool RsNxsGrp::serialise(void *data, uint32_t& size) const { @@ -519,20 +543,13 @@ RsNxsGrp* RsNxsSerialiser::deserialNxsGrpItem(void *data, uint32_t *size) } -RsNxsMsg* RsNxsSerialiser::deserialNxsMsgItem(void *data, uint32_t *size){ +RsNxsMsg* RsNxsSerialiser::deserialNxsMsgItem(void *data, uint32_t *size) +{ + if (!checkItemHeader(data, size, RS_PKT_SUBTYPE_NXS_MSG_ITEM)) return NULL; - bool ok = checkItemHeader(data,size,RS_PKT_SUBTYPE_NXS_MSG_ITEM); - uint32_t offset = 8; - - RsNxsMsg* item = new RsNxsMsg(SERVICE_TYPE); - /* skip the header */ - - ok &= getRawUInt32(data, *size, &offset, &(item->transactionNumber)); - ok &= getRawUInt8(data, *size, &offset, &(item->pos)); - ok &= item->msgId.deserialise(data, *size, offset); - ok &= item->grpId.deserialise(data, *size, offset); - ok &= item->msg.GetTlv(data, *size, &offset); - ok &= item->meta.GetTlv(data, *size, &offset); + RsNxsMsg* item = new RsNxsMsg(SERVICE_TYPE); + uint32_t offset = 0; + bool ok = item->deserialize(static_cast(data), *size, offset); if (offset != *size) { diff --git a/libretroshare/src/serialiser/rsnxsitems.h b/libretroshare/src/serialiser/rsnxsitems.h index 88f0ca914..ad450bd50 100644 --- a/libretroshare/src/serialiser/rsnxsitems.h +++ b/libretroshare/src/serialiser/rsnxsitems.h @@ -399,50 +399,39 @@ public: * Used to respond to a RsGrpMsgsReq * with message items satisfying request */ -class RsNxsMsg : public RsNxsItem +struct RsNxsMsg : RsNxsItem { -public: + RsNxsMsg(uint16_t servtype) : + RsNxsItem(servtype, RS_PKT_SUBTYPE_NXS_MSG_ITEM), meta(servtype), + msg(servtype), metaData(NULL) { clear(); } + virtual ~RsNxsMsg() { delete metaData; } - RsNxsMsg(uint16_t servtype) : RsNxsItem(servtype, RS_PKT_SUBTYPE_NXS_MSG_ITEM), meta(servtype), msg(servtype), - metaData(NULL) { - // std::cout << "\nrefcount++ : " << ++refcount << std::endl; - clear(); return; - } - virtual ~RsNxsMsg() - { - //std::cout << "\nrefcount-- : " << --refcount << std::endl; - if(metaData){ - //std::cout << "\ndeleted\n"; - delete metaData; - } - } + virtual uint32_t serial_size() const; + virtual bool serialise(void *data,uint32_t& size) const; + bool deserialize(const uint8_t* data, uint32_t& size, uint32_t& offset); - virtual bool serialise(void *data,uint32_t& size) const; - virtual uint32_t serial_size() const; - - virtual void clear(); - virtual std::ostream &print(std::ostream &out, uint16_t indent); + virtual void clear(); + virtual std::ostream &print(std::ostream &out, uint16_t indent); - uint8_t pos; /// used for splitting up msg - uint8_t count; /// number of split up messages - RsGxsGroupId grpId; /// group id, forms part of version id - RsGxsMessageId msgId; /// msg id - static int refcount; + uint8_t pos; /// used for splitting up msg + uint8_t count; /// number of split up messages + RsGxsGroupId grpId; /// group id, forms part of version id + RsGxsMessageId msgId; /// msg id + static int refcount; - /*! - * This should contains all the data - * which is not specific to the Gxs service data - */ - RsTlvBinaryData meta; + /*! + * This should contains all the data + * which is not specific to the Gxs service data + */ + RsTlvBinaryData meta; - /*! - * This contains Gxs specific data - * only client of API knows who to decode this - */ - RsTlvBinaryData msg; - - RsGxsMsgMetaData* metaData; + /*! + * This contains Gxs specific data + * only client of API knows how to decode this + */ + RsTlvBinaryData msg; + RsGxsMsgMetaData* metaData; }; /*! diff --git a/libretroshare/src/services/p3gxsmails.cpp b/libretroshare/src/services/p3gxsmails.cpp index 21bfc4460..6db2d2c6c 100644 --- a/libretroshare/src/services/p3gxsmails.cpp +++ b/libretroshare/src/services/p3gxsmails.cpp @@ -24,17 +24,6 @@ bool p3GxsMails::sendMail( GxsMailsClient::GxsMailSubServices service, const RsGxsId& own_gxsid, const RsGxsId& recipient, const uint8_t* data, uint32_t size, RsGxsMailBaseItem::EncryptionMode cm) -{ - std::vector recipients; - recipients.push_back(&recipient); - return sendMail(service, own_gxsid, recipients, data, size, cm); -} - -bool p3GxsMails::sendMail( GxsMailsClient::GxsMailSubServices service, - const RsGxsId& own_gxsid, - const std::vector& recipients, - const uint8_t* data, uint32_t size, - RsGxsMailBaseItem::EncryptionMode cm ) { std::cout << "p3GxsMails::sendEmail(...)" << std::endl; @@ -53,25 +42,9 @@ bool p3GxsMails::sendMail( GxsMailsClient::GxsMailSubServices service, return false; } - std::set rcps; - typedef std::vector::const_iterator itT; - for(itT it = recipients.begin(); it != recipients.end(); it++) + if(recipient.isNull()) { - const RsGxsId* gId = *it; - - if(!gId || gId->isNull()) - { - std::cerr << "p3GxsMails::sendEmail(...) got invalid recipient" - << std::endl; - print_stacktrace(); - return false; - } - - rcps.insert(*gId); - } - if(rcps.empty()) - { - std::cerr << "p3GxsMails::sendEmail(...) got no recipients" + std::cerr << "p3GxsMails::sendEmail(...) got invalid recipient" << std::endl; print_stacktrace(); return false; @@ -83,25 +56,22 @@ bool p3GxsMails::sendMail( GxsMailsClient::GxsMailSubServices service, item->meta.mAuthorId = own_gxsid; item->meta.mGroupId = preferredGroupId; item->cryptoType = cm; + item->saltRecipientHint(recipient); + item->saltRecipientHint(RsGxsId::random()); + item->receiptId = RSRandom::random_u64(); - typedef std::set::const_iterator siT; - for(siT it = rcps.begin(); it != rcps.end(); ++it) - item->saltRecipientHint(*it); - - // If there is jut one recipient salt with a random id to avoid leaking it - if(rcps.size() == 1) item->saltRecipientHint(RsGxsId::random()); - - /* At this point we do a lot of memory copying, it doesn't look pretty but - * ATM haven't thinked of an elegant way to have the GxsMailSubServices - * travelling encrypted withuot copying memory around or responsabilize the - * client service to embed it in data array that is awful */ + RsNxsMailPresignedReceipt nrcpt; + preparePresignedReceipt(*item, nrcpt); uint16_t serv = static_cast(service); - uint32_t clearTextPldSize = size+2; - item->payload.resize(clearTextPldSize); - uint32_t _discard = 0; - setRawUInt16(&item->payload[0], 2, &_discard, serv); - memcpy(&item->payload[2], data, size); + uint32_t rcptsize = nrcpt.serial_size(); + item->payload.resize(2 + rcptsize + size); + uint32_t offset = 0; + setRawUInt16(&item->payload[0], 2, &offset, serv); + nrcpt.serialise(&item->payload[offset], rcptsize); offset += rcptsize; + memcpy(&item->payload[offset], data, size); //offset += size; + + std::cout << "p3GxsMails::sendMail(...) receipt size: " << rcptsize << std::endl; switch (cm) { @@ -117,9 +87,9 @@ bool p3GxsMails::sendMail( GxsMailsClient::GxsMailSubServices service, uint8_t* encryptedData = NULL; uint32_t encryptedSize = 0; uint32_t encryptError = 0; - if( idService.encryptData( &item->payload[0], clearTextPldSize, + if( idService.encryptData( &item->payload[0], item->payload.size(), encryptedData, encryptedSize, - rcps, encryptError, true ) ) + recipient, encryptError, true ) ) { item->payload.resize(encryptedSize); memcpy(&item->payload[0], encryptedData, encryptedSize); @@ -143,8 +113,11 @@ bool p3GxsMails::sendMail( GxsMailsClient::GxsMailSubServices service, } uint32_t token; - std::cout << "p3GxsMails::sendEmail(...) sending mail to:"<< *recipients[0] - << " payload size: : " << item->payload.size() << std::endl; + std::cout << "p3GxsMails::sendEmail(...) sending mail to: "<< recipient + << " with cryptoType: " << item->cryptoType + << " recipientHint: " << item->recipientsHint + << " receiptId: " << item->receiptId + << " payload size: " << item->payload.size() << std::endl; publishMsg(token, item); return true; } @@ -230,8 +203,6 @@ void p3GxsMails::handleResponse(uint32_t token, uint32_t req_type) for( vT::const_iterator mIt = mv.begin(); mIt != mv.end(); ++mIt ) { RsGxsMsgItem* gItem = *mIt; - std::cout << "p3GxsMails::handleResponse(...) MAILS_UPDATE " - << (uint32_t)gItem->PacketSubType() << std::endl; switch(gItem->PacketSubType()) { case GXS_MAIL_SUBTYPE_MAIL: @@ -246,13 +217,48 @@ void p3GxsMails::handleResponse(uint32_t token, uint32_t req_type) break; } + std::cout << "p3GxsMails::handleResponse(...) MAILS_UPDATE " + << "GXS_MAIL_SUBTYPE_MAIL handling: " + << msg->meta.mMsgId + << " with cryptoType: "<< msg->cryptoType + << " recipientHint: " << msg->recipientsHint + << " receiptId: "<< msg->receiptId + << " payload.size(): " << msg->payload.size() + << std::endl; + handleEcryptedMail(msg); break; } + case GXS_MAIL_SUBTYPE_RECEIPT: + { + RsGxsMailPresignedReceipt* msg = + dynamic_cast(gItem); + if(!msg) + { + std::cerr << "p3GxsMails::handleResponse(...) " + << "GXS_MAIL_SUBTYPE_RECEIPT cast error, " + << "something really wrong is happening" + << std::endl; + break; + } + + std::cout << "p3GxsMails::handleResponse(...) MAILS_UPDATE " + << "GXS_MAIL_SUBTYPE_RECEIPT handling: " + << msg->meta.mMsgId + << "with receiptId: "<< msg->receiptId + << std::endl; + + /* TODO: Notify client services if the original mail was + * sent from this node and mark for deletion, otherwise + * just mark original mail for deletion. */ + + break; + } default: std::cerr << "p3GxsMails::handleResponse(...) MAILS_UPDATE " << "Unknown mail subtype : " - << gItem->PacketSubType() << std::endl; + << static_cast(gItem->PacketSubType()) + << std::endl; break; } delete gItem; @@ -262,7 +268,7 @@ void p3GxsMails::handleResponse(uint32_t token, uint32_t req_type) } default: std::cerr << "p3GxsMails::handleResponse(...) Unknown req_type: " - << req_type << std::endl; + << req_type << std::endl; break; } } @@ -285,13 +291,13 @@ void p3GxsMails::service_tick() reinterpret_cast(ciao.data()), ciao.size(), RsGxsMailBaseItem::RSA ); } - else if(idService.isOwnId(gxsidB)) - { - std::string ciao("CiBuono!"); - sendMail( GxsMailsClient::TEST_SERVICE, gxsidB, gxsidA, - reinterpret_cast(ciao.data()), - ciao.size(), RsGxsMailBaseItem::RSA ); - } +// else if(idService.isOwnId(gxsidB)) +// { +// std::string ciao("CiBuono!"); +// sendMail( GxsMailsClient::TEST_SERVICE, gxsidB, gxsidA, +// reinterpret_cast(ciao.data()), +// ciao.size(), RsGxsMailBaseItem::RSA ); +// } } GxsTokenQueue::checkRequests(); @@ -386,6 +392,8 @@ bool p3GxsMails::requestGroupsData(const std::list* groupIds) bool p3GxsMails::handleEcryptedMail(const RsGxsMailItem* mail) { + std::cout << "p3GxsMails::handleEcryptedMail(...)" << std::endl; + std::set decryptIds; std::list ownIds; idService.getOwnIds(ownIds); @@ -393,7 +401,11 @@ bool p3GxsMails::handleEcryptedMail(const RsGxsMailItem* mail) if(mail->maybeRecipient(*it)) decryptIds.insert(*it); // Hint match none of our own ids - if(decryptIds.empty()) return true; + if(decryptIds.empty()) + { + std::cout << "p3GxsMails::handleEcryptedMail(...) hint doesn't match" << std::endl; + return true; + } switch (mail->cryptoType) { @@ -409,17 +421,21 @@ bool p3GxsMails::handleEcryptedMail(const RsGxsMailItem* mail) } case RsGxsMailBaseItem::RSA: { - uint8_t* decrypted_data = NULL; - uint32_t decrypted_data_size = 0; - uint32_t decryption_error; bool ok = true; - if( idService.decryptData( &mail->payload[0], - mail->payload.size(), decrypted_data, - decrypted_data_size, decryptIds, - decryption_error ) ) - ok = dispatchDecryptedMail( mail, decrypted_data, - decrypted_data_size ); - free(decrypted_data); + for( std::set::const_iterator it = decryptIds.begin(); + it != decryptIds.end(); ++it ) + { + uint8_t* decrypted_data = NULL; + uint32_t decrypted_data_size = 0; + uint32_t decryption_error; + if( idService.decryptData( &mail->payload[0], + mail->payload.size(), decrypted_data, + decrypted_data_size, *it, + decryption_error ) ) + ok = ok && dispatchDecryptedMail( mail, decrypted_data, + decrypted_data_size ); + free(decrypted_data); + } return ok; } default: @@ -433,13 +449,37 @@ bool p3GxsMails::dispatchDecryptedMail( const RsGxsMailItem* received_msg, const uint8_t* decrypted_data, uint32_t decrypted_data_size ) { - std::cout << "p3GxsMails::dispatchDecryptedMail(, , " << decrypted_data_size << ")" << std::endl; + std::cout << "p3GxsMails::dispatchDecryptedMail(, , " << decrypted_data_size + << ")" << std::endl; + uint16_t csri = 0; - uint32_t off = 0; - getRawUInt16( decrypted_data, decrypted_data_size, &off, &csri); + uint32_t offset = 0; + if(!getRawUInt16( decrypted_data, decrypted_data_size, &offset, &csri)) + { + std::cerr << "p3GxsMails::dispatchDecryptedMail(...) (EE) fatal error " + << "deserializing service type, something really wrong is " + << "happening!" << std::endl; + return false; + } GxsMailsClient::GxsMailSubServices rsrvc; rsrvc = static_cast(csri); + RsNxsMailPresignedReceipt* receipt = new RsNxsMailPresignedReceipt(); + uint32_t rcptsize = decrypted_data_size; + if(!receipt->deserialize(decrypted_data, rcptsize, offset)) + { + std::cerr << "p3GxsMails::dispatchDecryptedMail(...) (EE) fatal error " + << "deserializing presigned return receipt , something really" + << " wrong is happening!" << std::endl; + delete receipt; + return false; + } + std::cout << "p3GxsMails::dispatchDecryptedMail(...) dispatching receipt " + << "with: msgId: " << receipt->msgId << std::endl; + + std::vector rcct; rcct.push_back(receipt); + RsGenExchange::notifyNewMessages(rcct); + GxsMailsClient* reecipientService = NULL; { RS_STACK_MUTEX(servClientsMutex); @@ -448,8 +488,8 @@ bool p3GxsMails::dispatchDecryptedMail( const RsGxsMailItem* received_msg, if(reecipientService) return reecipientService->receiveGxsMail( received_msg, - &decrypted_data[2], - decrypted_data_size-2 ); + &decrypted_data[offset], + decrypted_data_size-offset ); else { std::cerr << "p3GxsMails::dispatchReceivedMail(...) " @@ -459,3 +499,39 @@ bool p3GxsMails::dispatchDecryptedMail( const RsGxsMailItem* received_msg, } } +bool p3GxsMails::preparePresignedReceipt(const RsGxsMailItem& mail, RsNxsMailPresignedReceipt& receipt) +{ + RsGxsMailPresignedReceipt grcpt; + grcpt.meta = mail.meta; + grcpt.meta.mPublishTs = time(NULL); + grcpt.receiptId = mail.receiptId; + uint32_t groff = 0, grsz = grcpt.size(); + std::vector grsrz; + grsrz.resize(grsz); + grcpt.serialize(&grsrz[0], grsz, groff); + receipt.msg.setBinData(&grsrz[0], grsz); + + receipt.grpId = preferredGroupId; + receipt.metaData = new RsGxsMsgMetaData(); + *receipt.metaData = grcpt.meta; + + if(createMessage(&receipt) != CREATE_SUCCESS) + { + std::cout << "p3GxsMails::preparePresignedReceipt(...) receipt creation" + << " failed!" << std::endl; + return false; + } + + uint32_t metaSize = receipt.metaData->serial_size(); + std::vector srx; srx.resize(metaSize); + receipt.metaData->serialise(&srx[0], &metaSize); + receipt.meta.setBinData(&srx[0], metaSize); + + std::cout << "p3GxsMails::preparePresignedReceipt(...) prepared receipt" + << "with: grcpt.meta.mMsgId: " << grcpt.meta.mMsgId + << " msgId: " << receipt.msgId + << " metaData.mMsgId: " << receipt.metaData->mMsgId + << std::endl; + return true; +} + diff --git a/libretroshare/src/services/p3gxsmails.h b/libretroshare/src/services/p3gxsmails.h index 110e8fe47..0dac2c5a6 100644 --- a/libretroshare/src/services/p3gxsmails.h +++ b/libretroshare/src/services/p3gxsmails.h @@ -67,21 +67,6 @@ struct p3GxsMails : RsGenExchange, GxsTokenQueue RsGxsMailBaseItem::EncryptionMode cm = RsGxsMailBaseItem::RSA ); - /** - * Send an email to recipients, in the process author of the email is - * disclosed to the network (because the sent GXS item is signed), while - * recipients are not @see RsGxsMailBaseItem::recipientsHint for details on - * recipient protection. - * This method is part of the public interface of this service. - * @return true if the mail will be sent, false if not - */ - bool sendMail( GxsMailsClient::GxsMailSubServices service, - const RsGxsId& own_gxsid, - const std::vector& recipients, - const uint8_t* data, uint32_t size, - RsGxsMailBaseItem::EncryptionMode cm = RsGxsMailBaseItem::RSA - ); - /** * Register a client service to p3GxsMails to receive mails via * GxsMailsClient::receiveGxsMail(...) callback @@ -185,6 +170,9 @@ private: bool dispatchDecryptedMail( const RsGxsMailItem* received_msg, const uint8_t* decrypted_data, uint32_t decrypted_data_size ); + + bool preparePresignedReceipt( const RsGxsMailItem& mail, + RsNxsMailPresignedReceipt& receipt ); }; From e2468765130637988afaaaa0332dd9280dd34c22 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Mon, 20 Feb 2017 07:36:59 +0100 Subject: [PATCH 10/35] Cleanup GxsTokenQueue header --- libretroshare/src/gxs/gxstokenqueue.h | 38 ++++++++++++--------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/libretroshare/src/gxs/gxstokenqueue.h b/libretroshare/src/gxs/gxstokenqueue.h index 5787c1f28..4883fecbf 100644 --- a/libretroshare/src/gxs/gxstokenqueue.h +++ b/libretroshare/src/gxs/gxstokenqueue.h @@ -29,41 +29,37 @@ #include "util/rsthreads.h" -/* - * - * A little helper class, to manage callbacks from requests - * - */ - -class GxsTokenQueueItem +struct GxsTokenQueueItem { - public: - GxsTokenQueueItem(const uint32_t token, const uint32_t req_type) - :mToken(token),mReqType(req_type) { return; } - GxsTokenQueueItem(): mToken(0), mReqType(0) { return; } + GxsTokenQueueItem(const uint32_t token, const uint32_t req_type) : + mToken(token), mReqType(req_type) {} + + GxsTokenQueueItem(): mToken(0), mReqType(0) {} uint32_t mToken; uint32_t mReqType; }; +/** + * A little helper class, to manage callbacks from requests + */ class GxsTokenQueue { - public: +public: + GxsTokenQueue(RsGenExchange *gxs) : + mGenExchange(gxs), mQueueMtx("GxsTokenQueueMtx") {} - GxsTokenQueue(RsGenExchange *gxs) - :mGenExchange(gxs), mQueueMtx("GxsTokenQueueMtx") { return; } -bool queueRequest(uint32_t token, uint32_t req_type); + bool queueRequest(uint32_t token, uint32_t req_type); + void checkRequests(); /// must be called by -void checkRequests(); // must be called by +protected: - protected: + /// This must be overloaded to complete the functionality. + virtual void handleResponse(uint32_t token, uint32_t req_type); - // This must be overloaded to complete the functionality. -virtual void handleResponse(uint32_t token, uint32_t req_type); - - private: +private: RsGenExchange *mGenExchange; RsMutex mQueueMtx; std::list mQueue; From fcdb3d6c88265f24d7eac79ab3d0b02877b4f2ac Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Tue, 21 Feb 2017 11:43:18 +0100 Subject: [PATCH 11/35] RsGenExchange enum for create status --- libretroshare/src/gxs/rsgenexchange.cc | 3 --- libretroshare/src/gxs/rsgenexchange.h | 3 ++- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/libretroshare/src/gxs/rsgenexchange.cc b/libretroshare/src/gxs/rsgenexchange.cc index 1b2cb3f8f..323f6632c 100644 --- a/libretroshare/src/gxs/rsgenexchange.cc +++ b/libretroshare/src/gxs/rsgenexchange.cc @@ -83,9 +83,6 @@ RsGenExchange::RsGenExchange(RsGeneralDataService *gds, RsNetworkExchangeService mChecking(false), mLastCheck((int)time(NULL) - (int)(RSRandom::random_u32() % INTEGRITY_CHECK_PERIOD) + 120), // this helps unsynchronising the checks for the different services, with 2 min security to avoid checking right away before statistics come up. mIntegrityCheck(NULL), - CREATE_FAIL(0), - CREATE_SUCCESS(1), - CREATE_FAIL_TRY_LATER(2), SIGN_MAX_WAITING_TIME(60), SIGN_FAIL(0), SIGN_SUCCESS(1), diff --git a/libretroshare/src/gxs/rsgenexchange.h b/libretroshare/src/gxs/rsgenexchange.h index b918789c7..373d9ad30 100644 --- a/libretroshare/src/gxs/rsgenexchange.h +++ b/libretroshare/src/gxs/rsgenexchange.h @@ -878,8 +878,9 @@ private: RsGxsIntegrityCheck* mIntegrityCheck; protected: + enum CreateStatus { CREATE_FAIL, CREATE_SUCCESS, CREATE_FAIL_TRY_LATER }; + const uint8_t SIGN_MAX_WAITING_TIME; // TODO: cleanup this should be an enum! - const uint8_t CREATE_FAIL, CREATE_SUCCESS, CREATE_FAIL_TRY_LATER, SIGN_MAX_WAITING_TIME; const uint8_t SIGN_FAIL, SIGN_SUCCESS, SIGN_FAIL_TRY_LATER; const uint8_t VALIDATE_FAIL, VALIDATE_SUCCESS, VALIDATE_FAIL_TRY_LATER, VALIDATE_MAX_WAITING_TIME; From 1376b9f03164f81e224a2319014244162694b366 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Tue, 21 Feb 2017 12:02:27 +0100 Subject: [PATCH 12/35] p3GxsMails expose proper async API Moved testing code to TestGxsMailClientService RsGxsMailPresignedReceipt and RsGxsMailItem inherit RsGxsMailBaseItem p3GxsMails::sendMail(...) check paramenters and return immediately Added GxsMailsClient::notifySendMailStatus(...) to notify sent mails status Added p3GxsMails::querySendMailStatus(...) so clients can query status --- libretroshare/src/rsserver/rsinit.cc | 4 +- .../src/serialiser/rsgxsmailitems.cc | 16 +- libretroshare/src/serialiser/rsgxsmailitems.h | 165 +++---- libretroshare/src/services/p3gxsmails.cpp | 429 +++++++++++------- libretroshare/src/services/p3gxsmails.h | 141 +++++- 5 files changed, 455 insertions(+), 300 deletions(-) diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index ea1b1b33f..48c3569bd 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -1500,7 +1500,8 @@ int RsServer::StartupRetroShare() pqih->addService(gxsmails_ns, true); mConfigMgr->addConfiguration("gxs_mail.cfg", gxsmails_ns); - new TestGxsMailClientService(*mGxsMails); + TestGxsMailClientService* tgms = + new TestGxsMailClientService(*mGxsMails, *mGxsIdService); # endif // RS_GXS_MAIL // remove pword from memory @@ -1827,6 +1828,7 @@ int RsServer::StartupRetroShare() # ifdef RS_GXS_MAIL startServiceThread(mGxsMails, "gxs mail"); startServiceThread(gxsmails_ns, "gxs mail ns"); + tgms->start("Gxs Mail Test Service"); # endif // RS_GXS_MAIL #endif // RS_ENABLE_GXS diff --git a/libretroshare/src/serialiser/rsgxsmailitems.cc b/libretroshare/src/serialiser/rsgxsmailitems.cc index 38cd90140..f1a659d43 100644 --- a/libretroshare/src/serialiser/rsgxsmailitems.cc +++ b/libretroshare/src/serialiser/rsgxsmailitems.cc @@ -18,7 +18,7 @@ #include "serialiser/rsgxsmailitems.h" -const RsGxsId RsGxsMailBaseItem::allRecipientsHint("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); +const RsGxsId RsGxsMailItem::allRecipientsHint("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); bool RsGxsMailBaseItem::serialize(uint8_t* data, uint32_t size, @@ -26,9 +26,7 @@ bool RsGxsMailBaseItem::serialize(uint8_t* data, uint32_t size, { bool ok = setRsItemHeader(data, size, PacketId(), size); ok = ok && (offset += 8); // Take header in account - ok = ok && setRawUInt8(data, size, &offset, cryptoType); - ok = ok && recipientsHint.serialise(data, size, offset); - ok = ok && setRawUInt64(data, size, &offset, receiptId); + ok = ok && setRawUInt64(data, size, &offset, mailId); return ok; } @@ -39,18 +37,14 @@ bool RsGxsMailBaseItem::deserialize(const uint8_t* data, uint32_t& size, uint32_t rssize = getRsItemSize(dataPtr); uint32_t roffset = offset + 8; // Take header in account bool ok = rssize <= size; - uint8_t crType; - ok = ok && getRawUInt8(dataPtr, rssize, &roffset, &crType); - cryptoType = static_cast(crType); - ok = ok && recipientsHint.deserialise(dataPtr, rssize, roffset); - ok = ok && getRawUInt64(dataPtr, rssize, &roffset, &receiptId); + ok = ok && getRawUInt64(dataPtr, rssize, &roffset, &mailId); if(ok) { size = rssize; offset = roffset; } else size = 0; return ok; } -std::ostream&RsGxsMailBaseItem::print(std::ostream& out, uint16_t) -{ return out; } +std::ostream& RsGxsMailBaseItem::print(std::ostream &out, uint16_t) +{ return out << " RsGxsMailBaseItem::mailId: " << mailId; } bool RsGxsMailSerializer::serialise(RsItem* item, void* data, uint32_t* size) { diff --git a/libretroshare/src/serialiser/rsgxsmailitems.h b/libretroshare/src/serialiser/rsgxsmailitems.h index f215d10a2..4ec0094df 100644 --- a/libretroshare/src/serialiser/rsgxsmailitems.h +++ b/libretroshare/src/serialiser/rsgxsmailitems.h @@ -34,65 +34,55 @@ enum GxsMailItemsSubtypes GXS_MAIL_SUBTYPE_GROUP = 3 }; +typedef uint64_t RsGxsMailId; + struct RsNxsMailPresignedReceipt : RsNxsMsg { RsNxsMailPresignedReceipt() : RsNxsMsg(RS_SERVICE_TYPE_GXS_MAIL) {} }; -struct RsGxsMailPresignedReceipt : RsGxsMsgItem -{ - RsGxsMailPresignedReceipt() : - RsGxsMsgItem( RS_SERVICE_TYPE_GXS_MAIL, - static_cast(GXS_MAIL_SUBTYPE_RECEIPT) ), - receiptId(0) {} - - uint64_t receiptId; - - static uint32_t inline size() - { - return 8 + // Header - 8; // receiptId - } - bool serialize(uint8_t* data, uint32_t size, uint32_t& offset) const - { - bool ok = setRsItemHeader(data, size, PacketId(), size); - ok = ok && (offset += 8); // Take header in account - ok = ok && setRawUInt64(data, size, &offset, receiptId); - return ok; - } - bool deserialize(const uint8_t* data, uint32_t& size, uint32_t& offset) - { - void* dataPtr = reinterpret_cast(const_cast(data)); - uint32_t rssize = getRsItemSize(dataPtr); - uint32_t roffset = offset + 8; // Take header in account - bool ok = rssize <= size; - ok = ok && getRawUInt64(dataPtr, rssize, &roffset, &receiptId); - if(ok) { size = rssize; offset = roffset; } - else size = 0; - return ok; - } - - void clear() { receiptId = 0; } - std::ostream &print(std::ostream &out, uint16_t /*indent = 0*/) - { return out << receiptId; } -}; - - struct RsGxsMailBaseItem : RsGxsMsgItem { RsGxsMailBaseItem(GxsMailItemsSubtypes subtype) : RsGxsMsgItem( RS_SERVICE_TYPE_GXS_MAIL, - static_cast(subtype) ), - cryptoType(UNDEFINED_ENCRYPTION), receiptId(0) {} + static_cast(subtype) ), mailId(0) {} - /// Values must fit into uint8_t - enum EncryptionMode + RsGxsMailId mailId; + + void inline clear() { - CLEAR_TEXT = 1, - RSA = 2, - UNDEFINED_ENCRYPTION = 250 - }; - EncryptionMode cryptoType; + mailId = 0; + meta = RsMsgMetaData(); + } + + static uint32_t inline size() + { + return 8 + // Header + 8; // mailId + } + bool serialize(uint8_t* data, uint32_t size, uint32_t& offset) const; + bool deserialize(const uint8_t* data, uint32_t& size, uint32_t& offset); + std::ostream &print(std::ostream &out, uint16_t /*indent = 0*/); +}; + +struct RsGxsMailPresignedReceipt : RsGxsMailBaseItem +{ + RsGxsMailPresignedReceipt() : RsGxsMailBaseItem(GXS_MAIL_SUBTYPE_RECEIPT) {} +}; + +enum class RsGxsMailEncryptionMode : uint8_t +{ + CLEAR_TEXT = 1, + RSA = 2, + UNDEFINED_ENCRYPTION = 250 +}; + +struct RsGxsMailItem : RsGxsMailBaseItem +{ + RsGxsMailItem() : RsGxsMailBaseItem(GXS_MAIL_SUBTYPE_MAIL), + cryptoType(RsGxsMailEncryptionMode::UNDEFINED_ENCRYPTION) {} + + RsGxsMailEncryptionMode cryptoType; /** * @brief recipientsHint used instead of plain recipient id, so sender can @@ -130,65 +120,37 @@ struct RsGxsMailBaseItem : RsGxsMsgItem * corresponding hint may be fruit of a "luky" salting of another id. */ RsGxsId recipientsHint; - - void static inline saltRecipientHint(RsGxsId& hint, const RsGxsId& salt) - { hint = hint | salt; } void inline saltRecipientHint(const RsGxsId& salt) - { saltRecipientHint(recipientsHint, salt); } + { recipientsHint = recipientsHint | salt; } /** * @brief maybeRecipient given an id and an hint check if they match * @see recipientHint - * @note this is not the final implementation as id and hint are not 32bit - * integers it is just to not forget how to verify the hint/id matching - * fastly with boolean ops * @return true if the id may be recipient of the hint, false otherwise */ - bool static inline maybeRecipient(const RsGxsId& hint, const RsGxsId& id) - { return (~id|hint) == allRecipientsHint; } bool inline maybeRecipient(const RsGxsId& id) const - { return maybeRecipient(recipientsHint, id); } + { return (~id|recipientsHint) == allRecipientsHint; } const static RsGxsId allRecipientsHint; - uint64_t receiptId; - - void inline clear() - { - cryptoType = UNDEFINED_ENCRYPTION; - recipientsHint.clear(); - receiptId = 0; - meta = RsMsgMetaData(); - } - - static uint32_t inline size() - { - return 8 + // Header - 1 + // cryptoType - RsGxsId::serial_size() + // recipientsHint - 8; // receiptId - } - bool serialize(uint8_t* data, uint32_t size, uint32_t& offset) const; - bool deserialize(const uint8_t* data, uint32_t& size, uint32_t& offset); - std::ostream &print(std::ostream &out, uint16_t /*indent = 0*/); -}; - -struct RsGxsMailItem : RsGxsMailBaseItem -{ - RsGxsMailItem(GxsMailItemsSubtypes subtype) : - RsGxsMailBaseItem(subtype) {} - RsGxsMailItem() : - RsGxsMailBaseItem(GXS_MAIL_SUBTYPE_MAIL) {} - /** This should travel encrypted, unless EncryptionMode::CLEAR_TEXT * is specified */ std::vector payload; - uint32_t size() const { return RsGxsMailBaseItem::size() + payload.size(); } + uint32_t size() const + { + return RsGxsMailBaseItem::size() + + 1 + // cryptoType + recipientsHint.serial_size() + + payload.size(); + } bool serialize(uint8_t* data, uint32_t size, uint32_t& offset) const { bool ok = size < MAX_SIZE; ok = ok && RsGxsMailBaseItem::serialize(data, size, offset); + ok = ok && setRawUInt8( data, size, &offset, + static_cast(cryptoType) ); + ok = ok && recipientsHint.serialise(data, size, offset); uint32_t psz = payload.size(); ok = ok && memcpy(data+offset, &payload[0], psz); offset += psz; @@ -196,13 +158,28 @@ struct RsGxsMailItem : RsGxsMailBaseItem } bool deserialize(const uint8_t* data, uint32_t& size, uint32_t& offset) { - uint32_t bsz = RsGxsMailBaseItem::size(); - uint32_t psz = size - bsz; - return size < MAX_SIZE && size >= bsz - && RsGxsMailBaseItem::deserialize(data, size, offset) - && (payload.resize(psz), memcpy(&payload[0], data+offset, psz)); + void* dataPtr = reinterpret_cast(const_cast(data)); + uint32_t rssize = getRsItemSize(dataPtr); + uint32_t roffset = offset; + bool ok = rssize <= size && size < MAX_SIZE; + ok = ok && RsGxsMailBaseItem::deserialize(data, rssize, roffset); + uint8_t crType; + ok = ok && getRawUInt8(dataPtr, rssize, &roffset, &crType); + cryptoType = static_cast(crType); + ok = ok && recipientsHint.deserialise(dataPtr, rssize, roffset); + uint32_t psz = rssize - roffset; + ok = ok && (payload.resize(psz), memcpy(&payload[0], data+roffset, psz)); + if(ok) { size = rssize; offset = roffset; } + else size = 0; + return ok; + } + void clear() + { + RsGxsMailBaseItem::clear(); + cryptoType = RsGxsMailEncryptionMode::UNDEFINED_ENCRYPTION; + recipientsHint.clear(); + payload.clear(); } - void clear() { RsGxsMailBaseItem::clear(); payload.clear(); } /// Maximum mail size in bytes 10 MiB is more than anything sane can need const static uint32_t MAX_SIZE = 10*8*1024*1024; diff --git a/libretroshare/src/services/p3gxsmails.cpp b/libretroshare/src/services/p3gxsmails.cpp index 6db2d2c6c..ae7f3755d 100644 --- a/libretroshare/src/services/p3gxsmails.cpp +++ b/libretroshare/src/services/p3gxsmails.cpp @@ -20,21 +20,14 @@ #include "util/stacktrace.h" -bool p3GxsMails::sendMail( GxsMailsClient::GxsMailSubServices service, +bool p3GxsMails::sendMail( RsGxsMailId& mailId, + GxsMailsClient::GxsMailSubServices service, const RsGxsId& own_gxsid, const RsGxsId& recipient, const uint8_t* data, uint32_t size, - RsGxsMailBaseItem::EncryptionMode cm) + RsGxsMailEncryptionMode cm ) { std::cout << "p3GxsMails::sendEmail(...)" << std::endl; - if(preferredGroupId.isNull()) - { - requestGroupsData(); - std::cerr << "p3GxsMails::sendEmail(...) preferredGroupId.isNull()!" - << std::endl; - return false; - } - if(!idService.isOwnId(own_gxsid)) { std::cerr << "p3GxsMails::sendEmail(...) isOwnId(own_gxsid) false!" @@ -50,78 +43,31 @@ bool p3GxsMails::sendMail( GxsMailsClient::GxsMailSubServices service, return false; } - RsGxsMailItem* item = new RsGxsMailItem(); + OutgoingRecord pr( recipient, service, data, size ); + pr.mailItem.meta.mAuthorId = own_gxsid; + pr.mailItem.cryptoType = cm; + pr.mailItem.mailId = RSRandom::random_u64(); - // Public metadata - item->meta.mAuthorId = own_gxsid; - item->meta.mGroupId = preferredGroupId; - item->cryptoType = cm; - item->saltRecipientHint(recipient); - item->saltRecipientHint(RsGxsId::random()); - item->receiptId = RSRandom::random_u64(); - - RsNxsMailPresignedReceipt nrcpt; - preparePresignedReceipt(*item, nrcpt); - - uint16_t serv = static_cast(service); - uint32_t rcptsize = nrcpt.serial_size(); - item->payload.resize(2 + rcptsize + size); - uint32_t offset = 0; - setRawUInt16(&item->payload[0], 2, &offset, serv); - nrcpt.serialise(&item->payload[offset], rcptsize); offset += rcptsize; - memcpy(&item->payload[offset], data, size); //offset += size; - - std::cout << "p3GxsMails::sendMail(...) receipt size: " << rcptsize << std::endl; - - switch (cm) { - case RsGxsMailBaseItem::CLEAR_TEXT: - { - std::cerr << "p3GxsMails::sendMail(...) you are sending a mail without" - << " encryption, everyone can read it!" << std::endl; - print_stacktrace(); - break; - } - case RsGxsMailBaseItem::RSA: - { - uint8_t* encryptedData = NULL; - uint32_t encryptedSize = 0; - uint32_t encryptError = 0; - if( idService.encryptData( &item->payload[0], item->payload.size(), - encryptedData, encryptedSize, - recipient, encryptError, true ) ) - { - item->payload.resize(encryptedSize); - memcpy(&item->payload[0], encryptedData, encryptedSize); - free(encryptedData); - break; - } - else - { - std::cerr << "p3GxsMails::sendMail(...) RSA encryption failed! " - << "error_status: " << encryptError << std::endl; - print_stacktrace(); - return false; - } - } - case RsGxsMailBaseItem::UNDEFINED_ENCRYPTION: - default: - std::cerr << "p3GxsMails::sendMail(...) attempt to send mail with wrong" - << " EncryptionMode " << cm << " dropping mail!" << std::endl; - print_stacktrace(); - return false; + RS_STACK_MUTEX(outgoingMutex); + outgoingQueue.insert(prMap::value_type(pr.mailItem.mailId, pr)); } - uint32_t token; - std::cout << "p3GxsMails::sendEmail(...) sending mail to: "<< recipient - << " with cryptoType: " << item->cryptoType - << " recipientHint: " << item->recipientsHint - << " receiptId: " << item->receiptId - << " payload size: " << item->payload.size() << std::endl; - publishMsg(token, item); + mailId = pr.mailItem.mailId; return true; } +bool p3GxsMails::querySendMailStatus(RsGxsMailId mailId, GxsMailStatus& st) +{ + auto it = outgoingQueue.find(mailId); + if( it != outgoingQueue.end() ) + { + st = it->second.status; + return true; + } + return false; +} + void p3GxsMails::registerGxsMailsClient( GxsMailsClient::GxsMailSubServices serviceType, GxsMailsClient* service) { @@ -132,7 +78,8 @@ void p3GxsMails::registerGxsMailsClient( void p3GxsMails::handleResponse(uint32_t token, uint32_t req_type) { - //std::cout << "p3GxsMails::handleResponse(" << token << ", " << req_type << ")" << std::endl; + std::cout << "p3GxsMails::handleResponse(" << token << ", " << req_type + << ")" << std::endl; switch (req_type) { case GROUPS_LIST: @@ -202,66 +149,34 @@ void p3GxsMails::handleResponse(uint32_t token, uint32_t req_type) vT& mv(gIt->second); for( vT::const_iterator mIt = mv.begin(); mIt != mv.end(); ++mIt ) { - RsGxsMsgItem* gItem = *mIt; - switch(gItem->PacketSubType()) + RsGxsMsgItem* gIt = *mIt; + switch(gIt->PacketSubType()) { case GXS_MAIL_SUBTYPE_MAIL: + case GXS_MAIL_SUBTYPE_RECEIPT: { - RsGxsMailItem* msg = dynamic_cast(gItem); - if(!msg) + RsGxsMailBaseItem* mb = + dynamic_cast(*mIt); + if(mb) { + RS_STACK_MUTEX(ingoingMutex); + ingoingQueue.insert(inMap::value_type(mb->mailId, mb)); + } + else std::cerr << "p3GxsMails::handleResponse(...) " << "GXS_MAIL_SUBTYPE_MAIL cast error, " << "something really wrong is happening" << std::endl; - break; - } - - std::cout << "p3GxsMails::handleResponse(...) MAILS_UPDATE " - << "GXS_MAIL_SUBTYPE_MAIL handling: " - << msg->meta.mMsgId - << " with cryptoType: "<< msg->cryptoType - << " recipientHint: " << msg->recipientsHint - << " receiptId: "<< msg->receiptId - << " payload.size(): " << msg->payload.size() - << std::endl; - - handleEcryptedMail(msg); - break; - } - case GXS_MAIL_SUBTYPE_RECEIPT: - { - RsGxsMailPresignedReceipt* msg = - dynamic_cast(gItem); - if(!msg) - { - std::cerr << "p3GxsMails::handleResponse(...) " - << "GXS_MAIL_SUBTYPE_RECEIPT cast error, " - << "something really wrong is happening" - << std::endl; - break; - } - - std::cout << "p3GxsMails::handleResponse(...) MAILS_UPDATE " - << "GXS_MAIL_SUBTYPE_RECEIPT handling: " - << msg->meta.mMsgId - << "with receiptId: "<< msg->receiptId - << std::endl; - - /* TODO: Notify client services if the original mail was - * sent from this node and mark for deletion, otherwise - * just mark original mail for deletion. */ - break; } default: std::cerr << "p3GxsMails::handleResponse(...) MAILS_UPDATE " << "Unknown mail subtype : " - << static_cast(gItem->PacketSubType()) + << static_cast(gIt->PacketSubType()) << std::endl; + delete gIt; break; } - delete gItem; } } break; @@ -275,32 +190,52 @@ void p3GxsMails::handleResponse(uint32_t token, uint32_t req_type) void p3GxsMails::service_tick() { - static int tc = 0; - ++tc; + GxsTokenQueue::checkRequests(); - if(((tc % 1000) == 0) || (tc == 50)) requestGroupsData(); - - if(tc == 500) { - RsGxsId gxsidA("d0df7474bdde0464679e6ef787890287"); - RsGxsId gxsidB("d060bea09dfa14883b5e6e517eb580cd"); - if(idService.isOwnId(gxsidA)) + RS_STACK_MUTEX(outgoingMutex); + for ( auto it = outgoingQueue.begin(); it != outgoingQueue.end(); ) { - std::string ciao("CiAone!"); - sendMail( GxsMailsClient::TEST_SERVICE, gxsidA, gxsidB, - reinterpret_cast(ciao.data()), - ciao.size(), RsGxsMailBaseItem::RSA ); + OutgoingRecord& pr(it->second); + GxsMailStatus oldStatus = pr.status; + processOutgoingRecord(pr); + if (oldStatus != pr.status) notifyClientService(pr); + if( pr.status >= GxsMailStatus::RECEIPT_RECEIVED ) + it = outgoingQueue.erase(it); + else ++it; } -// else if(idService.isOwnId(gxsidB)) -// { -// std::string ciao("CiBuono!"); -// sendMail( GxsMailsClient::TEST_SERVICE, gxsidB, gxsidA, -// reinterpret_cast(ciao.data()), -// ciao.size(), RsGxsMailBaseItem::RSA ); -// } } - GxsTokenQueue::checkRequests(); + + { + RS_STACK_MUTEX(ingoingMutex); + for( auto it = ingoingQueue.begin(); it != ingoingQueue.end(); ) + { + if( it->second->PacketSubType() != GXS_MAIL_SUBTYPE_MAIL ) + { ++it; continue; } + + RsGxsMailItem* msg = dynamic_cast(it->second); + if(!msg) + { + std::cout << "p3GxsMails::service_tick() GXS_MAIL_SUBTYPE_MAIL" + << "dynamic_cast failed, something really wrong is " + << "happening!" << std::endl; + ++it; continue; + } + + std::cout << "p3GxsMails::service_tick() GXS_MAIL_SUBTYPE_MAIL " + << "handling: " << msg->meta.mMsgId + << " with cryptoType: " + << static_cast(msg->cryptoType) + << " recipientHint: " << msg->recipientsHint + << " mailId: "<< msg->mailId + << " payload.size(): " << msg->payload.size() + << std::endl; + + handleEcryptedMail(msg); + it = ingoingQueue.erase(it); delete msg; + } + } } RsGenExchange::ServiceCreate_Return p3GxsMails::service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySet& /*keySet*/) @@ -409,7 +344,7 @@ bool p3GxsMails::handleEcryptedMail(const RsGxsMailItem* mail) switch (mail->cryptoType) { - case RsGxsMailBaseItem::CLEAR_TEXT: + case RsGxsMailEncryptionMode::CLEAR_TEXT: { uint16_t csri = 0; uint32_t off = 0; @@ -419,7 +354,7 @@ bool p3GxsMails::handleEcryptedMail(const RsGxsMailItem* mail) return dispatchDecryptedMail( mail, &mail->payload[0], mail->payload.size() ); } - case RsGxsMailBaseItem::RSA: + case RsGxsMailEncryptionMode::RSA: { bool ok = true; for( std::set::const_iterator it = decryptIds.begin(); @@ -440,7 +375,7 @@ bool p3GxsMails::handleEcryptedMail(const RsGxsMailItem* mail) } default: std::cout << "Unknown encryption type:" - << mail->cryptoType << std::endl; + << static_cast(mail->cryptoType) << std::endl; return false; } } @@ -487,7 +422,7 @@ bool p3GxsMails::dispatchDecryptedMail( const RsGxsMailItem* received_msg, } if(reecipientService) - return reecipientService->receiveGxsMail( received_msg, + return reecipientService->receiveGxsMail( *received_msg, &decrypted_data[offset], decrypted_data_size-offset ); else @@ -499,39 +434,189 @@ bool p3GxsMails::dispatchDecryptedMail( const RsGxsMailItem* received_msg, } } -bool p3GxsMails::preparePresignedReceipt(const RsGxsMailItem& mail, RsNxsMailPresignedReceipt& receipt) +void p3GxsMails::processOutgoingRecord(OutgoingRecord& pr) { - RsGxsMailPresignedReceipt grcpt; - grcpt.meta = mail.meta; - grcpt.meta.mPublishTs = time(NULL); - grcpt.receiptId = mail.receiptId; - uint32_t groff = 0, grsz = grcpt.size(); - std::vector grsrz; - grsrz.resize(grsz); - grcpt.serialize(&grsrz[0], grsz, groff); - receipt.msg.setBinData(&grsrz[0], grsz); + //std::cout << "p3GxsMails::processRecord(...)" << std::endl; - receipt.grpId = preferredGroupId; - receipt.metaData = new RsGxsMsgMetaData(); - *receipt.metaData = grcpt.meta; - - if(createMessage(&receipt) != CREATE_SUCCESS) + switch (pr.status) { - std::cout << "p3GxsMails::preparePresignedReceipt(...) receipt creation" - << " failed!" << std::endl; - return false; + case GxsMailStatus::PENDING_PROCESSING: + { + pr.mailItem.saltRecipientHint(pr.recipient); + pr.mailItem.saltRecipientHint(RsGxsId::random()); } + case GxsMailStatus::PENDING_PREFERRED_GROUP: + { + if(preferredGroupId.isNull()) + { + requestGroupsData(); + pr.status = GxsMailStatus::PENDING_PREFERRED_GROUP; + break; + } - uint32_t metaSize = receipt.metaData->serial_size(); - std::vector srx; srx.resize(metaSize); - receipt.metaData->serialise(&srx[0], &metaSize); - receipt.meta.setBinData(&srx[0], metaSize); + pr.mailItem.meta.mGroupId = preferredGroupId; + } + case GxsMailStatus::PENDING_RECEIPT_CREATE: + { + RsGxsMailPresignedReceipt grcpt; + grcpt.meta = pr.mailItem.meta; + grcpt.meta.mPublishTs = time(NULL); + grcpt.mailId = pr.mailItem.mailId; + uint32_t groff = 0, grsz = grcpt.size(); + std::vector grsrz; + grsrz.resize(grsz); + grcpt.serialize(&grsrz[0], grsz, groff); - std::cout << "p3GxsMails::preparePresignedReceipt(...) prepared receipt" - << "with: grcpt.meta.mMsgId: " << grcpt.meta.mMsgId - << " msgId: " << receipt.msgId - << " metaData.mMsgId: " << receipt.metaData->mMsgId - << std::endl; - return true; + pr.presignedReceipt.grpId = preferredGroupId; + pr.presignedReceipt.metaData = new RsGxsMsgMetaData(); + *pr.presignedReceipt.metaData = grcpt.meta; + pr.presignedReceipt.msg.setBinData(&grsrz[0], grsz); + } + case GxsMailStatus::PENDING_RECEIPT_SIGNATURE: + { + switch (RsGenExchange::createMessage(&pr.presignedReceipt)) + { + case CREATE_SUCCESS: break; + case CREATE_FAIL_TRY_LATER: + pr.status = GxsMailStatus::PENDING_RECEIPT_CREATE; + return; + default: + pr.status = GxsMailStatus::FAILED_RECEIPT_SIGNATURE; + goto processingFailed; + } + + uint32_t metaSize = pr.presignedReceipt.metaData->serial_size(); + std::vector srx; srx.resize(metaSize); + pr.presignedReceipt.metaData->serialise(&srx[0], &metaSize); + pr.presignedReceipt.meta.setBinData(&srx[0], metaSize); + } + case GxsMailStatus::PENDING_PAYLOAD_CREATE: + { + uint16_t serv = static_cast(pr.clientService); + uint32_t rcptsize = pr.presignedReceipt.serial_size(); + uint32_t datasize = pr.mailData.size(); + pr.mailItem.payload.resize(2 + rcptsize + datasize); + uint32_t offset = 0; + setRawUInt16(&pr.mailItem.payload[0], 2, &offset, serv); + pr.presignedReceipt.serialise( &pr.mailItem.payload[offset], + rcptsize ); + offset += rcptsize; + memcpy(&pr.mailItem.payload[offset], &pr.mailData[0], datasize); + } + case GxsMailStatus::PENDING_PAYLOAD_ENCRYPT: + { + switch (pr.mailItem.cryptoType) + { + case RsGxsMailEncryptionMode::CLEAR_TEXT: + { + std::cerr << "p3GxsMails::sendMail(...) you are sending a mail " + << "without encryption, everyone can read it!" + << std::endl; + break; + } + case RsGxsMailEncryptionMode::RSA: + { + uint8_t* encryptedData = NULL; + uint32_t encryptedSize = 0; + uint32_t encryptError = 0; + if( idService.encryptData( &pr.mailItem.payload[0], + pr.mailItem.payload.size(), + encryptedData, encryptedSize, + pr.recipient, encryptError, true ) ) + { + pr.mailItem.payload.resize(encryptedSize); + memcpy( &pr.mailItem.payload[0], encryptedData, + encryptedSize ); + free(encryptedData); + break; + } + else + { + std::cerr << "p3GxsMails::sendMail(...) RSA encryption failed! " + << "error_status: " << encryptError << std::endl; + pr.status = GxsMailStatus::FAILED_ENCRYPTION; + goto processingFailed; + } + } + case RsGxsMailEncryptionMode::UNDEFINED_ENCRYPTION: + default: + std::cerr << "p3GxsMails::sendMail(...) attempt to send mail with " + << "wrong EncryptionMode: " + << static_cast(pr.mailItem.cryptoType) + << " dropping mail!" << std::endl; + pr.status = GxsMailStatus::FAILED_ENCRYPTION; + goto processingFailed; + } + } + case GxsMailStatus::PENDING_PUBLISH: + { + std::cout << "p3GxsMails::sendEmail(...) sending mail to: " + << pr.recipient + << " with cryptoType: " + << static_cast(pr.mailItem.cryptoType) + << " recipientHint: " << pr.mailItem.recipientsHint + << " receiptId: " << pr.mailItem.mailId + << " payload size: " << pr.mailItem.payload.size() + << std::endl; + + uint32_t token; + publishMsg(token, new RsGxsMailItem(pr.mailItem)); + pr.status = GxsMailStatus::PENDING_RECEIPT_RECEIVE; + break; + } + //case GxsMailStatus::PENDING_TRANSFER: + case GxsMailStatus::PENDING_RECEIPT_RECEIVE: + { + RS_STACK_MUTEX(ingoingMutex); + auto it = ingoingQueue.find(pr.mailItem.mailId); + if (it == ingoingQueue.end()) break; + RsGxsMailPresignedReceipt* rt = + dynamic_cast(it->second); + if( !rt || !idService.isOwnId(rt->meta.mAuthorId) ) break; + + ingoingQueue.erase(it); delete rt; + pr.status = GxsMailStatus::RECEIPT_RECEIVED; + // TODO: Malicious adversary could forge messages with same mailId and + // could end up overriding the legit receipt in ingoingQueue, and + // causing also a memleak(using unordered_multimap for ingoingQueue + // may fix this?) + // TODO: Resend message if older then treshold + } + case GxsMailStatus::RECEIPT_RECEIVED: + break; + +processingFailed: + case GxsMailStatus::FAILED_RECEIPT_SIGNATURE: + case GxsMailStatus::FAILED_ENCRYPTION: + default: + { + std::cout << "p3GxsMails::processRecord(" << pr.mailItem.mailId + << ") failed with: " << static_cast(pr.status) + << std::endl; + break; + } + } +} + +void p3GxsMails::notifyClientService(const OutgoingRecord& pr) +{ + RS_STACK_MUTEX(servClientsMutex); + auto it = servClients.find(pr.clientService); + if( it != servClients.end()) + { + GxsMailsClient* serv(it->second); + if(serv) + { + serv->notifySendMailStatus(pr.mailItem, pr.status); + return; + } + } + + std::cerr << "p3GxsMails::processRecord(...) (EE) processed" + << " mail for unkown service: " + << static_cast(pr.clientService) + << " fatally failed with: " + << static_cast(pr.status) << std::endl; + print_stacktrace(); } diff --git a/libretroshare/src/services/p3gxsmails.h b/libretroshare/src/services/p3gxsmails.h index 0dac2c5a6..dcbed0937 100644 --- a/libretroshare/src/services/p3gxsmails.h +++ b/libretroshare/src/services/p3gxsmails.h @@ -23,9 +23,27 @@ #include "gxs/gxstokenqueue.h" // For GxsTokenQueue #include "serialiser/rsgxsmailitems.h" // For RS_SERVICE_TYPE_GXS_MAIL #include "services/p3idservice.h" // For p3IdService +#include "util/rsthreads.h" + +enum class GxsMailStatus +{ + PENDING_PROCESSING = 0, + PENDING_PREFERRED_GROUP, + PENDING_RECEIPT_CREATE, + PENDING_RECEIPT_SIGNATURE, + PENDING_SERIALIZATION, + PENDING_PAYLOAD_CREATE, + PENDING_PAYLOAD_ENCRYPT, + PENDING_PUBLISH, + //PENDING_TRANSFER, /// This will be useful so the user can know if the mail reached some friend node, in case of internet connection interruption + PENDING_RECEIPT_RECEIVE, + /// Records with status >= RECEIPT_RECEIVED get deleted + RECEIPT_RECEIVED, + FAILED_RECEIPT_SIGNATURE = 240, + FAILED_ENCRYPTION +}; struct p3GxsMails; - struct GxsMailsClient { /// Subservices identifiers (like port for TCP) @@ -38,10 +56,12 @@ struct GxsMailsClient * @param dataSize size of the buffer * @return true if dispatching goes fine, false otherwise */ - virtual bool receiveGxsMail( const RsGxsMailItem* originalMessage, + virtual bool receiveGxsMail( const RsGxsMailItem& originalMessage, const uint8_t* data, uint32_t dataSize ) = 0; -}; + virtual bool notifySendMailStatus( const RsGxsMailItem& originalMessage, + GxsMailStatus status ) = 0; +}; struct p3GxsMails : RsGenExchange, GxsTokenQueue { @@ -51,7 +71,9 @@ struct p3GxsMails : RsGenExchange, GxsTokenQueue RS_SERVICE_TYPE_GXS_MAIL, &identities, AuthenPolicy(), GXS_STORAGE_PERIOD ), GxsTokenQueue(this), idService(identities), - servClientsMutex("p3GxsMails client services map mutex") {} + servClientsMutex("p3GxsMails client services map mutex"), + outgoingMutex("p3GxsMails outgoing queue map mutex"), + ingoingMutex("p3GxsMails ingoing queue map mutex") {} /** * Send an email to recipient, in the process author of the email is @@ -61,37 +83,43 @@ struct p3GxsMails : RsGenExchange, GxsTokenQueue * This method is part of the public interface of this service. * @return true if the mail will be sent, false if not */ - bool sendMail( GxsMailsClient::GxsMailSubServices service, + bool sendMail( RsGxsMailId& mailId, + GxsMailsClient::GxsMailSubServices service, const RsGxsId& own_gxsid, const RsGxsId& recipient, const uint8_t* data, uint32_t size, - RsGxsMailBaseItem::EncryptionMode cm = RsGxsMailBaseItem::RSA + RsGxsMailEncryptionMode cm = RsGxsMailEncryptionMode::RSA ); + /** + * This method is part of the public interface of this service. + * @return false if mail is not found in outgoing queue, true otherwise + */ + bool querySendMailStatus( RsGxsMailId mailId, GxsMailStatus& st ); + /** * Register a client service to p3GxsMails to receive mails via * GxsMailsClient::receiveGxsMail(...) callback + * This method is part of the public interface of this service. */ void registerGxsMailsClient( GxsMailsClient::GxsMailSubServices serviceType, GxsMailsClient* service ); + /// @see RsGenExchange::getServiceInfo() + virtual RsServiceInfo getServiceInfo() { return RsServiceInfo( RS_SERVICE_TYPE_GXS_MAIL, "GXS Mails", 0, 1, 0, 1 ); } +private: /// @see GxsTokenQueue::handleResponse(uint32_t token, uint32_t req_type) virtual void handleResponse(uint32_t token, uint32_t req_type); /// @see RsGenExchange::service_tick() virtual void service_tick(); - /// @see RsGenExchange::getServiceInfo() - virtual RsServiceInfo getServiceInfo() { return RsServiceInfo( RS_SERVICE_TYPE_GXS_MAIL, "GXS Mails", 0, 1, 0, 1 ); } - /// @see RsGenExchange::service_CreateGroup(...) RsGenExchange::ServiceCreate_Return service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySet&); -protected: /// @see RsGenExchange::notifyChanges(std::vector &changes) void notifyChanges(std::vector &changes); -private: /** Time interval of inactivity before a distribution group is unsubscribed. * Approximatively 3 months seems ok ATM. */ const static int32_t UNUSED_GROUP_UNSUBSCRIBE_INTERVAL = 0x76A700; @@ -101,7 +129,7 @@ private: * very fast taking in account we are handling mails for the whole network. * We do prefer to resend a not acknowledged yet mail after * GXS_STORAGE_PERIOD has passed and keep it little. - * Tought it can't be too little as this may cause signed acknowledged to + * Tought it can't be too little as this may cause signed receipts to * get lost thus causing resend and fastly grow perceived async latency, in * case two sporadically connected users sends mails each other. * TODO: While it is ok for signed acknowledged to stays in the DB for a @@ -132,6 +160,33 @@ private: std::map servClients; RsMutex servClientsMutex; + struct OutgoingRecord + { + OutgoingRecord( RsGxsId rec, GxsMailsClient::GxsMailSubServices cs, + const uint8_t* data, uint32_t size ) : + status(GxsMailStatus::PENDING_PROCESSING), recipient(rec), + clientService(cs) + { + mailData.resize(size); + memcpy(&mailData[0], data, size); + } + + GxsMailStatus status; + RsGxsId recipient; + RsGxsMailItem mailItem; /// Don't use a pointer would be invalid after publish + std::vector mailData; + GxsMailsClient::GxsMailSubServices clientService; + RsNxsMailPresignedReceipt presignedReceipt; + }; + /// Keep track of mails while being processed + typedef std::map prMap; + prMap outgoingQueue; + RsMutex outgoingMutex; + void processOutgoingRecord(OutgoingRecord& r); + + typedef std::map inMap; + inMap ingoingQueue; + RsMutex ingoingMutex; /// Request groups list to GXS backend. Async method. bool requestGroupsData(const std::list* groupIds = NULL); @@ -171,27 +226,69 @@ private: const uint8_t* decrypted_data, uint32_t decrypted_data_size ); - bool preparePresignedReceipt( const RsGxsMailItem& mail, - RsNxsMailPresignedReceipt& receipt ); + void notifyClientService(const OutgoingRecord& pr); }; - -struct TestGxsMailClientService : GxsMailsClient +struct TestGxsMailClientService : GxsMailsClient, RsSingleJobThread { - TestGxsMailClientService(p3GxsMails& gmxMailService) + TestGxsMailClientService( p3GxsMails& gxsMailService, + p3IdService& gxsIdService ) : + mailService(gxsMailService), idService(gxsIdService) { - gmxMailService.registerGxsMailsClient( GxsMailSubServices::TEST_SERVICE, - this ); + mailService.registerGxsMailsClient( GxsMailSubServices::TEST_SERVICE, + this ); } /// @see GxsMailsClient::receiveGxsMail(...) - virtual bool receiveGxsMail( const RsGxsMailItem* originalMessage, + virtual bool receiveGxsMail( const RsGxsMailItem& originalMessage, const uint8_t* data, uint32_t dataSize ) { std::cout << "TestGxsMailClientService::receiveGxsMail(...) got message" - << " from: " << originalMessage->meta.mAuthorId << std::endl - << "\t" << std::string((char*)data, dataSize) << std::endl; + << " from: " << originalMessage.meta.mAuthorId << std::endl + << "\t>" << std::string((char*)data, dataSize) << "<" + << std::endl; return true; } + + /// @see GxsMailsClient::notifyMailStatus(...) + virtual bool notifySendMailStatus( const RsGxsMailItem& originalMessage, + GxsMailStatus status ) + { + std::cout << "TestGxsMailClientService::notifyMailsStatus(...) for: " + << originalMessage.mailId << " status: " + << static_cast(status) << std::endl; + if( status == GxsMailStatus::RECEIPT_RECEIVED ) + std::cout << "\t It mean Receipt has been Received!" << std::endl; + return true; + } + + /// @see RsSingleJobThread::run() + virtual void run() + { + usleep(10*1000*1000); + RsGxsId gxsidA("d0df7474bdde0464679e6ef787890287"); + RsGxsId gxsidB("d060bea09dfa14883b5e6e517eb580cd"); + RsGxsMailId mailId = 0; + if(idService.isOwnId(gxsidA)) + { + std::string ciao("CiAone!"); + mailService.sendMail( mailId, GxsMailsClient::TEST_SERVICE, gxsidA, + gxsidB, + reinterpret_cast(ciao.data()), + ciao.size() ); + } + else if(idService.isOwnId(gxsidB)) + { + std::string ciao("CiBuono!"); + mailService.sendMail( mailId, GxsMailsClient::TEST_SERVICE, gxsidB, + gxsidA, + reinterpret_cast(ciao.data()), + ciao.size() ); + } + } + +private: + p3GxsMails& mailService; + p3IdService& idService; }; From b9091c4ad8f30351ca424baece05bd27ce347916 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Tue, 21 Feb 2017 23:08:02 +0100 Subject: [PATCH 13/35] p3MsgService uses p3GxsMails as backend too --- libretroshare/src/rsserver/rsinit.cc | 2 +- libretroshare/src/services/p3gxsmails.h | 2 +- libretroshare/src/services/p3msgservice.cc | 711 +++++++++++++-------- libretroshare/src/services/p3msgservice.h | 45 +- 4 files changed, 485 insertions(+), 275 deletions(-) diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index 48c3569bd..b33dcef1d 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -1513,7 +1513,7 @@ int RsServer::StartupRetroShare() p3ServiceInfo *serviceInfo = new p3ServiceInfo(serviceCtrl); mDisc = new p3discovery2(mPeerMgr, mLinkMgr, mNetMgr, serviceCtrl); mHeart = new p3heartbeat(serviceCtrl, pqih); - msgSrv = new p3MsgService(serviceCtrl,mGxsIdService); + msgSrv = new p3MsgService( serviceCtrl, mGxsIdService, *mGxsMails ); chatSrv = new p3ChatService(serviceCtrl,mGxsIdService, mLinkMgr, mHistoryMgr); mStatusSrv = new p3StatusService(serviceCtrl); diff --git a/libretroshare/src/services/p3gxsmails.h b/libretroshare/src/services/p3gxsmails.h index dcbed0937..9184f7074 100644 --- a/libretroshare/src/services/p3gxsmails.h +++ b/libretroshare/src/services/p3gxsmails.h @@ -47,7 +47,7 @@ struct p3GxsMails; struct GxsMailsClient { /// Subservices identifiers (like port for TCP) - enum GxsMailSubServices { TEST_SERVICE = 1 }; + enum GxsMailSubServices : uint16_t { TEST_SERVICE = 1, P3_MSG_SERVICE = 2 }; /** * This will be called by p3GxsMails to dispatch mails to the subservice diff --git a/libretroshare/src/services/p3msgservice.cc b/libretroshare/src/services/p3msgservice.cc index f5dbed520..e4b302443 100644 --- a/libretroshare/src/services/p3msgservice.cc +++ b/libretroshare/src/services/p3msgservice.cc @@ -83,23 +83,29 @@ static const uint32_t RS_MSG_DISTANT_MESSAGE_HASH_KEEP_TIME = 2*30*86400 ; // ke * (3) from storage... */ -p3MsgService::p3MsgService(p3ServiceControl *sc, p3IdService *id_serv) - :p3Service(), p3Config(), mIdService(id_serv), mServiceCtrl(sc), mMsgMtx("p3MsgService"), mMsgUniqueId(0) +p3MsgService::p3MsgService( p3ServiceControl *sc, p3IdService *id_serv, + p3GxsMails& gxsMS ) + : p3Service(), p3Config(), mIdService(id_serv), mServiceCtrl(sc), + mMsgMtx("p3MsgService"), mMsgUniqueId(0), gxsMailService(gxsMS), + gxsOngoingMutex("p3MsgService Gxs Outgoing Mutex"), + recentlyReceivedMutex("p3MsgService recently received hash mutex") { - _serialiser = new RsMsgSerialiser(); // 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); - mMsgUniqueId = 1 ; // MsgIds are not transmitted, but only used locally as a storage index. As such, thay do not need to be different - // at friends nodes. - - mShouldEnableDistantMessaging = true ; - mDistantMessagingEnabled = false ; - mDistantMessagePermissions = RS_DISTANT_MESSAGING_CONTACT_PERMISSION_FLAG_FILTER_NONE ; + /* MsgIds are not transmitted, but only used locally as a storage index. + * As such, thay do not need to be different at friends nodes. */ + mMsgUniqueId = 1; - /* Initialize standard tag types */ - if(sc) - initStandardTagTypes(); + mShouldEnableDistantMessaging = true; + mDistantMessagingEnabled = false; + mDistantMessagePermissions = RS_DISTANT_MESSAGING_CONTACT_PERMISSION_FLAG_FILTER_NONE; + if(sc) initStandardTagTypes(); // Initialize standard tag types + + gxsMailService.registerGxsMailsClient(GxsMailsClient::P3_MSG_SERVICE, this); } const std::string MSG_APP_NAME = "msg"; @@ -141,11 +147,11 @@ int p3MsgService::tick() if(now > last_management_time + 5) { - manageDistantPeers() ; - checkOutgoingMessages(); - cleanListOfReceivedMessageHashes(); + manageDistantPeers(); + checkOutgoingMessages(); + cleanListOfReceivedMessageHashes(); - last_management_time = now ; + last_management_time = now; } return 0; @@ -153,21 +159,21 @@ int p3MsgService::tick() void p3MsgService::cleanListOfReceivedMessageHashes() { - RS_STACK_MUTEX(mMsgMtx); /********** STACK LOCKED MTX ******/ + RS_STACK_MUTEX(recentlyReceivedMutex); - time_t now = time(NULL) ; - - for(std::map::iterator it(mRecentlyReceivedDistantMessageHashes.begin());it!=mRecentlyReceivedDistantMessageHashes.end();) - if(now > RS_MSG_DISTANT_MESSAGE_HASH_KEEP_TIME + it->second) - { - std::cerr << "p3MsgService(): cleanListOfReceivedMessageHashes(). Removing old hash " << it->first << ", aged " << now - it->second << " secs ago" << std::endl; - std::map::iterator tmp(it) ; - ++tmp ; - mRecentlyReceivedDistantMessageHashes.erase(it) ; - it=tmp ; - } - else - ++it ; + time_t now = time(NULL); + + for( auto it = mRecentlyReceivedMessageHashes.begin(); + it != mRecentlyReceivedMessageHashes.end(); ) + if( now > RS_MSG_DISTANT_MESSAGE_HASH_KEEP_TIME + it->second ) + { + std::cerr << "p3MsgService(): cleanListOfReceivedMessageHashes(). " + << "Removing old hash " << it->first << ", aged " + << now - it->second << " secs ago" << std::endl; + + it = mRecentlyReceivedMessageHashes.erase(it); + } + else ++it; } int p3MsgService::status() @@ -348,107 +354,102 @@ void p3MsgService::checkSizeAndSendMessage(RsMsgItem *msg) sendItem(msg) ; } -int p3MsgService::checkOutgoingMessages() +int p3MsgService::checkOutgoingMessages() { - /* iterate through the outgoing queue - * - * if online, send - */ + bool changed = false; + std::list output_queue; - bool changed = false ; - std::list output_queue ; + { + RS_STACK_MUTEX(mMsgMtx); /********** STACK LOCKED MTX ******/ - { - RS_STACK_MUTEX(mMsgMtx); /********** STACK LOCKED MTX ******/ - - const RsPeerId& ownId = mServiceCtrl->getOwnId(); + const RsPeerId& ownId = mServiceCtrl->getOwnId(); - std::list::iterator it; - std::list toErase; + std::list::iterator it; + std::list toErase; - std::map::iterator mit; - for(mit = msgOutgoing.begin(); mit != msgOutgoing.end(); ++mit) - { - if (mit->second->msgFlags & RS_MSG_FLAGS_TRASH) - continue; + std::map::iterator mit; + for( mit = msgOutgoing.begin(); mit != msgOutgoing.end(); ++mit ) + { + if (mit->second->msgFlags & RS_MSG_FLAGS_TRASH) continue; - /* find the certificate */ - RsPeerId pid = mit->second->PeerId(); - bool should_send = false ; + /* find the certificate */ + RsPeerId pid = mit->second->PeerId(); + bool should_send = false; - if( pid == ownId) - should_send = true ; + if( pid == ownId) should_send = true; - if( mServiceCtrl->isPeerConnected(getServiceInfo().mServiceType, pid) ) /* FEEDBACK Msg to Ourselves */ - should_send = true ; + // FEEDBACK Msg to Ourselves + if( mServiceCtrl->isPeerConnected(getServiceInfo().mServiceType, + pid) ) + should_send = true; - if((mit->second->msgFlags & RS_MSG_FLAGS_DISTANT) && !(mit->second->msgFlags & RS_MSG_FLAGS_ROUTED)) - should_send = true ; + if( (mit->second->msgFlags & RS_MSG_FLAGS_DISTANT) && + !(mit->second->msgFlags & RS_MSG_FLAGS_ROUTED)) + should_send = true; - if(should_send) - { - /* send msg */ - pqioutput(PQL_DEBUG_BASIC, msgservicezone, - "p3MsgService::checkOutGoingMessages() Sending out message"); - /* remove the pending flag */ + if(should_send) + { + /* send msg */ + pqioutput( PQL_DEBUG_BASIC, msgservicezone, + "p3MsgService::checkOutGoingMessages() Sending out message"); + /* remove the pending flag */ - output_queue.push_back(mit->second) ; + output_queue.push_back(mit->second) ; - // When the message is a distant msg, dont remove it yet from the list. Only mark it as being sent, so that we don't send it again. - // - if(!(mit->second->msgFlags & RS_MSG_FLAGS_DISTANT)) - { - (mit->second)->msgFlags &= ~RS_MSG_FLAGS_PENDING; - toErase.push_back(mit->first); - changed = true ; - } - else - { + /* When the message is a distant msg, dont remove it yet from + * the list. Only mark it as being sent, so that we don't send + * it again. */ + if(!(mit->second->msgFlags & RS_MSG_FLAGS_DISTANT)) + { + (mit->second)->msgFlags &= ~RS_MSG_FLAGS_PENDING; + toErase.push_back(mit->first); + changed = true; + } + else + { #ifdef DEBUG_DISTANT_MSG - std::cerr << "Message id " << mit->first << " is distant: kept in outgoing, and marked as ROUTED" << std::endl; + std::cerr << "Message id " << mit->first << " is distant: " + << "kept in outgoing, and marked as ROUTED" + << std::endl; #endif - mit->second->msgFlags |= RS_MSG_FLAGS_ROUTED ; - } - } - else - { - pqioutput(PQL_DEBUG_BASIC, msgservicezone, - "p3MsgService::checkOutGoingMessages() Delaying until available..."); - } - } + mit->second->msgFlags |= RS_MSG_FLAGS_ROUTED; + } + } + else + { + pqioutput( PQL_DEBUG_BASIC, msgservicezone, + "p3MsgService::checkOutGoingMessages() Delaying until available..."); + } + } - /* clean up */ - for(it = toErase.begin(); it != toErase.end(); ++it) - { - mit = msgOutgoing.find(*it); - if (mit != msgOutgoing.end()) - { - msgOutgoing.erase(mit); - } + /* clean up */ + for(it = toErase.begin(); it != toErase.end(); ++it) + { + mit = msgOutgoing.find(*it); + if ( mit != msgOutgoing.end() ) msgOutgoing.erase(mit); - std::map::iterator srcIt = mSrcIds.find(*it); - if (srcIt != mSrcIds.end()) { - delete (srcIt->second); - mSrcIds.erase(srcIt); - } - } + std::map::iterator srcIt = mSrcIds.find(*it); + if (srcIt != mSrcIds.end()) + { + delete (srcIt->second); + mSrcIds.erase(srcIt); + } + } - if (toErase.size() > 0) - { - IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/ - } - } + if (toErase.size() > 0) IndicateConfigChanged(); + } - for(std::list::const_iterator it(output_queue.begin());it!=output_queue.end();++it) - if((*it)->msgFlags & RS_MSG_FLAGS_DISTANT) // don't split distant messages. The global router takes care of it. - sendDistantMsgItem(*it) ; - else - checkSizeAndSendMessage(*it) ; + for( std::list::const_iterator it(output_queue.begin()); + it != output_queue.end(); ++it ) + if( (*it)->msgFlags & RS_MSG_FLAGS_DISTANT ) // don't split distant messages. The global router takes care of it. + sendDistantMsgItem(*it); + else + checkSizeAndSendMessage(*it); - if(changed) - RsServer::notify()->notifyListChange(NOTIFY_LIST_MESSAGELIST,NOTIFY_TYPE_MOD); + if(changed) + RsServer::notify()->notifyListChange(NOTIFY_LIST_MESSAGELIST,NOTIFY_TYPE_MOD); - return 0; + return 0; } bool p3MsgService::saveList(bool& cleanup, std::list& itemList) @@ -489,10 +490,13 @@ bool p3MsgService::saveList(bool& cleanup, std::list& itemList) grmap->ongoing_msgs = _ongoing_messages ; itemList.push_back(grmap) ; - - RsMsgDistantMessagesHashMap *ghm = new RsMsgDistantMessagesHashMap ; - ghm->hash_map = mRecentlyReceivedDistantMessageHashes ; - itemList.push_back(ghm) ; + + RsMsgDistantMessagesHashMap *ghm = new RsMsgDistantMessagesHashMap; + { + RS_STACK_MUTEX(recentlyReceivedMutex); + ghm->hash_map = mRecentlyReceivedMessageHashes; + } + itemList.push_back(ghm); RsConfigKeyValueSet *vitem = new RsConfigKeyValueSet ; RsTlvKeyValue kv; @@ -601,18 +605,21 @@ bool p3MsgService::loadList(std::list& load) // merge. for(std::map::const_iterator it(grm->ongoing_msgs.begin());it!=grm->ongoing_msgs.end();++it) _ongoing_messages.insert(*it) ; - } - else if(NULL != (ghm = dynamic_cast(*it))) - { - mRecentlyReceivedDistantMessageHashes = ghm->hash_map ; - + } + else if(NULL != (ghm = dynamic_cast(*it))) + { + { + RS_STACK_MUTEX(recentlyReceivedMutex); + mRecentlyReceivedMessageHashes = ghm->hash_map; + } + #ifdef DEBUG_DISTANT_MSG std::cerr << " loaded recently received message map: " << std::endl; for(std::map::const_iterator it(mRecentlyReceivedDistantMessageHashes.begin());it!=mRecentlyReceivedDistantMessageHashes.end();++it) std::cerr << " " << it->first << " received " << time(NULL)-it->second << " secs ago." << std::endl; #endif - } + } else if(NULL != (mtt = dynamic_cast(*it))) { // delete standard tags as they are now save in config @@ -1107,16 +1114,17 @@ uint32_t p3MsgService::sendMessage(RsMsgItem *item) // no from field because return item->msgId; } -uint32_t p3MsgService::sendDistantMessage(RsMsgItem *item,const RsGxsId& from) -{ - if(!item) - return 0 ; - item->msgId = getNewUniqueMsgId(); /* grabs Mtx as well */ - item->msgFlags |= (RS_MSG_FLAGS_DISTANT | RS_MSG_FLAGS_OUTGOING | RS_MSG_FLAGS_PENDING); /* add pending flag */ +uint32_t p3MsgService::sendDistantMessage(RsMsgItem *item, const RsGxsId& from) +{ + if(!item) return 0; + + item->msgId = getNewUniqueMsgId(); /* grabs Mtx as well */ + item->msgFlags |= ( RS_MSG_FLAGS_DISTANT | RS_MSG_FLAGS_OUTGOING | + RS_MSG_FLAGS_PENDING ); /* add pending flag */ { - RS_STACK_MUTEX(mMsgMtx) ; + RS_STACK_MUTEX(mMsgMtx); /* STORE MsgID */ msgOutgoing[item->msgId] = item; @@ -1128,17 +1136,16 @@ uint32_t p3MsgService::sendDistantMessage(RsMsgItem *item,const RsGxsId& fro RsMsgSrcId* msi = new RsMsgSrcId(); msi->msgId = item->msgId; - msi->srcId = RsPeerId(from) ; + msi->srcId = RsPeerId(from); mSrcIds.insert(std::pair(msi->msgId, msi)); } } IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/ - RsServer::notify()->notifyListChange(NOTIFY_LIST_MESSAGELIST, NOTIFY_TYPE_ADD); - + RsServer::notify()->notifyListChange( NOTIFY_LIST_MESSAGELIST, + NOTIFY_TYPE_ADD ); return item->msgId; - } bool p3MsgService::MessageSend(MessageInfo &info) @@ -1853,73 +1860,89 @@ void p3MsgService::manageDistantPeers() } } -void p3MsgService::notifyDataStatus(const GRouterMsgPropagationId& id, const RsGxsId &signer_id, uint32_t data_status) +void p3MsgService::notifyDataStatus( const GRouterMsgPropagationId& id, + const RsGxsId &signer_id, + uint32_t data_status ) { - if(data_status == GROUTER_CLIENT_SERVICE_DATA_STATUS_FAILED) - { - RS_STACK_MUTEX(mMsgMtx); /********** STACK LOCKED MTX ******/ + if(data_status == GROUTER_CLIENT_SERVICE_DATA_STATUS_FAILED) + { + RS_STACK_MUTEX(mMsgMtx); - std::cerr << "(WW) p3MsgService::notifyDataStatus: Global router tells us that item ID " << id << " could not be delivered on time." ; - std::map::iterator it = _ongoing_messages.find(id) ; - - if(it == _ongoing_messages.end()) - { - std::cerr << " (EE) cannot find pending message to acknowledge. Weird. grouter id = " << id << std::endl; - return ; - } - uint32_t msg_id = it->second ; - std::cerr << " message id = " << msg_id << std::endl; - mDistantOutgoingMsgSigners[msg_id] = signer_id ; // this is needed because it's not saved in config, but we should probably include it in _ongoing_messages + std::cerr << "(WW) p3MsgService::notifyDataStatus: Global router tells " + << "us that item ID " << id + << " could not be delivered on time."; - std::map::iterator mit = msgOutgoing.find(msg_id) ; + auto it = _ongoing_messages.find(id); + if(it == _ongoing_messages.end()) + { + std::cerr << " (EE) cannot find pending message to acknowledge. " + << "Weird. grouter id = " << id << std::endl; + return; + } - if(mit == msgOutgoing.end()) - { - std::cerr << " (EE) message has been notified as not delivered, but it not on outgoing list. Something's wrong!!" << std::endl; - return ; - } - std::cerr << " reseting the ROUTED flag so that the message is requested again" << std::endl; + uint32_t msg_id = it->second; + std::cerr << " message id = " << msg_id << std::endl; - mit->second->msgFlags &= ~RS_MSG_FLAGS_ROUTED ; // clear the routed flag so that the message is requested again - return ; - } - - if(data_status == GROUTER_CLIENT_SERVICE_DATA_STATUS_RECEIVED) - { - RS_STACK_MUTEX(mMsgMtx); /********** STACK LOCKED MTX ******/ + /* this is needed because it's not saved in config, but we should + * probably include it in _ongoing_messages */ + mDistantOutgoingMsgSigners[msg_id] = signer_id; + + std::map::iterator mit = msgOutgoing.find(msg_id); + + if(mit == msgOutgoing.end()) + { + std::cerr << " (EE) message has been notified as not delivered, " + << "but it not on outgoing list. Something's wrong!!" + << std::endl; + return; + } + std::cerr << " reseting the ROUTED flag so that the message is " + << "requested again" << std::endl; + + // clear the routed flag so that the message is requested again + mit->second->msgFlags &= ~RS_MSG_FLAGS_ROUTED; + return; + } + + if(data_status == GROUTER_CLIENT_SERVICE_DATA_STATUS_RECEIVED) + { + RS_STACK_MUTEX(mMsgMtx); #ifdef DEBUG_DISTANT_MSG - std::cerr << "p3MsgService::acknowledgeDataReceived(): acknowledging data received for msg propagation id " << id << std::endl; + std::cerr << "p3MsgService::acknowledgeDataReceived(): acknowledging data received for msg propagation id " << id << std::endl; #endif - std::map::iterator it = _ongoing_messages.find(id) ; + auto it = _ongoing_messages.find(id); + if(it == _ongoing_messages.end()) + { + std::cerr << " (EE) cannot find pending message to acknowledge. " + << "Weird. grouter id = " << id << std::endl; + return; + } - if(it == _ongoing_messages.end()) - { - std::cerr << " (EE) cannot find pending message to acknowledge. Weird. grouter id = " << id << std::endl; - return ; - } + uint32_t msg_id = it->second ; - uint32_t msg_id = it->second ; + // we should now remove the item from the msgOutgoing list. - // we should now remove the item from the msgOutgoing list. + std::map::iterator it2 = msgOutgoing.find(msg_id); + if(it2 == msgOutgoing.end()) + { + std::cerr << "(EE) message has been ACKed, but is not in outgoing " + << "list. Something's wrong!!" << std::endl; + return; + } - std::map::iterator it2 = msgOutgoing.find(msg_id) ; + delete it2->second; + msgOutgoing.erase(it2); - if(it2 == msgOutgoing.end()) - { - std::cerr << "(EE) message has been ACKed, but is not in outgoing list. Something's wrong!!" << std::endl; - return ; - } + RsServer::notify()->notifyListChange( NOTIFY_LIST_MESSAGELIST, + NOTIFY_TYPE_ADD ); + IndicateConfigChanged(); - delete it2->second ; - msgOutgoing.erase(it2) ; - - RsServer::notify()->notifyListChange(NOTIFY_LIST_MESSAGELIST,NOTIFY_TYPE_ADD); - IndicateConfigChanged() ; - - return ; - } - std::cerr << "p3MsgService: unhandled data status info from global router for msg ID " << id << ": this is a bug." << std::endl; + return; + } + std::cerr << "p3MsgService: unhandled data status info from global router" + << " for msg ID " << id << ": this is a bug." << std::endl; } + bool p3MsgService::acceptDataFromPeer(const RsGxsId& to_gxs_id) { if(mDistantMessagePermissions & RS_DISTANT_MESSAGING_CONTACT_PERMISSION_FLAG_FILTER_NON_CONTACTS) @@ -1945,104 +1968,274 @@ uint32_t p3MsgService::getDistantMessagingPermissionFlags() { return mDistantMessagePermissions ; } - -void p3MsgService::receiveGRouterData(const RsGxsId &destination_key, const RsGxsId &signing_key, GRouterServiceId &/*client_id*/, uint8_t *data, uint32_t data_size) + +bool p3MsgService::receiveGxsMail( const RsGxsMailItem& originalMessage, + const uint8_t* data, uint32_t dataSize ) { - std::cerr << "p3MsgService::receiveGRouterData(): received message item of size " << data_size << ", for key " << destination_key << std::endl; + Sha1CheckSum hash = RsDirUtil::sha1sum(data, dataSize); - // first make sure that we havn't already received the data. Since we allow to re-send messages, it's necessary to check. - - Sha1CheckSum hash = RsDirUtil::sha1sum(data,data_size) ; - - if(mRecentlyReceivedDistantMessageHashes.find(hash) != mRecentlyReceivedDistantMessageHashes.end()) - { - std::cerr << "(WW) receiving distant message of hash " << hash << " more than once. This is not a bug, unless it happens very often." << std::endl; + { + RS_STACK_MUTEX(recentlyReceivedMutex); + if( mRecentlyReceivedMessageHashes.find(hash) != + mRecentlyReceivedMessageHashes.end() ) + { + std::cerr << "p3MsgService::receiveGxsMail(...) (WW) receiving " + << "message of hash " << hash << " more than once. This " + << "is not a bug, unless it happens very often." + << std::endl; + return true; + } + mRecentlyReceivedMessageHashes[hash] = time(NULL); + } + + IndicateConfigChanged(); + + RsItem *item = _serialiser->deserialise(const_cast(data), &dataSize); + RsMsgItem *msg_item = dynamic_cast(item); + + if(msg_item) + { + std::cerr << "p3MsgService::receiveGxsMail(...) Encrypted item " + << "correctly deserialised. Passing on to incoming list." + << std::endl; + + msg_item->msgFlags |= RS_MSG_FLAGS_DISTANT; + /* we expect complete msgs - remove partial flag just in case + * someone has funny ideas */ + msg_item->msgFlags &= ~RS_MSG_FLAGS_PARTIAL; + + // hack to pass on GXS id. + msg_item->PeerId(RsPeerId(originalMessage.meta.mAuthorId)); + handleIncomingItem(msg_item); + } + else + std::cerr << "p3MsgService::receiveGxsMail(...) Item could not be " + << "deserialised. Format error??" << std::endl; +} + +bool p3MsgService::notifySendMailStatus( const RsGxsMailItem& originalMessage, + GxsMailStatus status ) +{ + if( status >= GxsMailStatus::FAILED_RECEIPT_SIGNATURE ) + { + uint32_t msg_id; + + { + RS_STACK_MUTEX(gxsOngoingMutex); + + std::cerr << "p3MsgService::notifySendMailStatus(...) mail delivery" + << "mailId: " << originalMessage.mailId + << " failed with " << static_cast(status); + + auto it = gxsOngoingMessages.find(originalMessage.mailId); + if(it == gxsOngoingMessages.end()) + { + std::cerr << " cannot find pending message to notify" + << std::endl; + return false; + } + + msg_id = it->second; + } + + std::cerr << " message id = " << msg_id << std::endl; + + { + RS_STACK_MUTEX(mMsgMtx); + auto mit = msgOutgoing.find(msg_id); + if( mit == msgOutgoing.end() ) + { + std::cerr << " message has been notified as not delivered, " + << "but it not on outgoing list." + << std::endl; + return true; + } + std::cerr << " reseting the ROUTED flag so that the message is " + << "requested again" << std::endl; + + // clear the routed flag so that the message is requested again + mit->second->msgFlags &= ~RS_MSG_FLAGS_ROUTED; + return true; + } + } + + if( status == GxsMailStatus::RECEIPT_RECEIVED ) + { + uint32_t msg_id; + + { + RS_STACK_MUTEX(gxsOngoingMutex); + + auto it = gxsOngoingMessages.find(originalMessage.mailId); + if(it == gxsOngoingMessages.end()) + { + std::cerr << " (EE) cannot find pending message to acknowledge. " + << "Weird.mailId = " << originalMessage.mailId + << std::endl; + return false; + } + + msg_id = it->second; + } + + // we should now remove the item from the msgOutgoing list. + + { + RS_STACK_MUTEX(mMsgMtx); + + auto it2 = msgOutgoing.find(msg_id); + if(it2 == msgOutgoing.end()) + { + std::cerr << "(EE) message has been ACKed, but is not in " + << "outgoing list. Something's wrong!!" << std::endl; + return true; + } + + delete it2->second; + msgOutgoing.erase(it2); + } + + RsServer::notify()->notifyListChange( NOTIFY_LIST_MESSAGELIST, + NOTIFY_TYPE_ADD ); + IndicateConfigChanged(); + + return true; + } +} + +void p3MsgService::receiveGRouterData( const RsGxsId &destination_key, + const RsGxsId &signing_key, + GRouterServiceId &/*client_id*/, + uint8_t *data, uint32_t data_size ) +{ + std::cerr << "p3MsgService::receiveGRouterData(): received message item of" + << " size " << data_size << ", for key " << destination_key + << std::endl; + + /* first make sure that we havn't already received the data. Since we allow + * to re-send messages, it's necessary to check. */ + + Sha1CheckSum hash = RsDirUtil::sha1sum(data, data_size); + + { + RS_STACK_MUTEX(recentlyReceivedMutex); + if( mRecentlyReceivedMessageHashes.find(hash) != + mRecentlyReceivedMessageHashes.end() ) + { + std::cerr << "p3MsgService::receiveGRouterData(...) (WW) receiving" + << "distant message of hash " << hash << " more than once" + << ". This is not a bug, unless it happens very often." + << std::endl; + free(data); + return; + } + mRecentlyReceivedMessageHashes[hash] = time(NULL); + } + + IndicateConfigChanged() ; + + RsItem *item = _serialiser->deserialise(data,&data_size) ; free(data) ; - return ; - } - mRecentlyReceivedDistantMessageHashes[hash] = time(NULL) ; - IndicateConfigChanged() ; - - RsItem *item = _serialiser->deserialise(data,&data_size) ; - free(data) ; - RsMsgItem *msg_item = dynamic_cast(item) ; + RsMsgItem *msg_item = dynamic_cast(item) ; - if(msg_item != NULL) - { - std::cerr << " Encrypted item correctly deserialised. Passing on to incoming list." << std::endl; + if(msg_item != NULL) + { + std::cerr << " Encrypted item correctly deserialised. Passing on to incoming list." << std::endl; - msg_item->msgFlags |= RS_MSG_FLAGS_DISTANT ; - /* we expect complete msgs - remove partial flag just in case someone has funny ideas */ - msg_item->msgFlags &= ~RS_MSG_FLAGS_PARTIAL; + msg_item->msgFlags |= RS_MSG_FLAGS_DISTANT ; + /* we expect complete msgs - remove partial flag just in case someone has funny ideas */ + msg_item->msgFlags &= ~RS_MSG_FLAGS_PARTIAL; - msg_item->PeerId(RsPeerId(signing_key)) ; // hack to pass on GXS id. - handleIncomingItem(msg_item) ; - } - else - std::cerr << " Item could not be deserialised. Format error??" << std::endl; + msg_item->PeerId(RsPeerId(signing_key)) ; // hack to pass on GXS id. + handleIncomingItem(msg_item) ; + } + else + std::cerr << " Item could not be deserialised. Format error??" << std::endl; } void p3MsgService::sendDistantMsgItem(RsMsgItem *msgitem) { - RsGxsId destination_key_id(msgitem->PeerId()) ; - RsGxsId signing_key_id ; + RsGxsId destination_key_id(msgitem->PeerId()); + RsGxsId signing_key_id; - msgitem->msgFlags |= RS_MSG_FLAGS_DISTANT ;// just in case, but normally we should always have this flag set, when ending up here. - - { - RS_STACK_MUTEX(mMsgMtx) ; + /* just in case, but normally we should always have this flag set, when + * ending up here. */ + msgitem->msgFlags |= RS_MSG_FLAGS_DISTANT; - std::map::const_iterator it = mDistantOutgoingMsgSigners.find(msgitem->msgId) ; - - if(it == mDistantOutgoingMsgSigners.end()) - { - std::cerr << "(EE) no signer registered for distant message " << msgitem->msgId << ". Cannot send!" << std::endl; - return ; - } - - signing_key_id = it->second ; + { + RS_STACK_MUTEX(mMsgMtx); - if(signing_key_id.isNull()) - { - std::cerr << "ERROR: cannot find signing key id for msg id " << msgitem->msgId << std::endl; - std::cerr << " available keys are:" << std::endl; - for(std::map::const_iterator it(mDistantOutgoingMsgSigners.begin());it!=mDistantOutgoingMsgSigners.end();++it) - std::cerr << " " << it->first << " " << it->second << std::endl; - return ; - } - } + std::map::const_iterator it = + mDistantOutgoingMsgSigners.find(msgitem->msgId); + + if(it == mDistantOutgoingMsgSigners.end()) + { + std::cerr << "(EE) no signer registered for distant message " + << msgitem->msgId << ". Cannot send!" << std::endl; + return; + } + + signing_key_id = it->second; + + if(signing_key_id.isNull()) + { + std::cerr << "ERROR: cannot find signing key id for msg id " + << msgitem->msgId << " available keys are:" << std::endl; + typedef std::map::const_iterator itT; + for( itT it = mDistantOutgoingMsgSigners.begin(); + it != mDistantOutgoingMsgSigners.end(); ++it ) + std::cerr << "\t" << it->first << " " << it->second + << std::endl; + return; + } + } #ifdef DEBUG_DISTANT_MSG - std::cerr << "p3MsgService::sendDistanteMsgItem(): sending distant msg item" << std::endl; - std::cerr << " msg ID : " << msgitem->msgId << std::endl; - std::cerr << " to peer : " << destination_key_id << std::endl; - std::cerr << " signing : " << signing_key_id << std::endl; + std::cerr << "p3MsgService::sendDistanteMsgItem(): sending distant msg item" + << " msg ID: " << msgitem->msgId << " to peer:" + << destination_key_id << " signing: " << signing_key_id + << std::endl; #endif - // 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 + /* 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 */ - uint32_t msg_serialized_rssize = msgitem->serial_size(false) ; - RsTemporaryMemory msg_serialized_data(msg_serialized_rssize) ; + uint32_t msg_serialized_rssize = msgitem->serial_size(false); + RsTemporaryMemory msg_serialized_data(msg_serialized_rssize); - if(!msgitem->serialise(msg_serialized_data,msg_serialized_rssize,false)) - { - std::cerr << "(EE) p3MsgService::sendTurtleData(): Serialization error." << std::endl; - return ; - } + if(!msgitem->serialise(msg_serialized_data,msg_serialized_rssize,false)) + { + std::cerr << "(EE) p3MsgService::sendTurtleData(): Serialization error." + << std::endl; + return; + } #ifdef DEBUG_DISTANT_MSG - std::cerr << " serialised size : " << msg_serialized_rssize << std::endl; + std::cerr << " serialised size : " << msg_serialized_rssize << std::endl; #endif - GRouterMsgPropagationId grouter_message_id ; - mGRouter->sendData(destination_key_id,GROUTER_CLIENT_ID_MESSAGES,msg_serialized_data,msg_serialized_rssize,signing_key_id,grouter_message_id) ; + GRouterMsgPropagationId grouter_message_id; + mGRouter->sendData( destination_key_id, GROUTER_CLIENT_ID_MESSAGES, + msg_serialized_data, msg_serialized_rssize, + signing_key_id, grouter_message_id ); + RsGxsMailId gxsMailId; + gxsMailService.sendMail( gxsMailId, P3_MSG_SERVICE, signing_key_id, + destination_key_id, msg_serialized_data, + msg_serialized_rssize ); - // now store the grouter id along with the message id, so that we can keep track of received messages + /* now store the grouter id along with the message id, so that we can keep + * track of received messages */ - { - RS_STACK_MUTEX(mMsgMtx) ; - _ongoing_messages[grouter_message_id] = msgitem->msgId ; - } - IndicateConfigChanged(); // save _ongoing_messages + { + RS_STACK_MUTEX(mMsgMtx); + _ongoing_messages[grouter_message_id] = msgitem->msgId; + } + + { + RS_STACK_MUTEX(gxsOngoingMutex); + gxsOngoingMessages[gxsMailId] = msgitem->msgId; + } + + IndicateConfigChanged(); // save _ongoing_messages } diff --git a/libretroshare/src/services/p3msgservice.h b/libretroshare/src/services/p3msgservice.h index a36486514..a40dfd704 100644 --- a/libretroshare/src/services/p3msgservice.h +++ b/libretroshare/src/services/p3msgservice.h @@ -49,16 +49,19 @@ #include "grouter/grouterclientservice.h" #include "turtle/p3turtle.h" #include "turtle/turtleclientservice.h" +#include "services/p3gxsmails.h" class p3LinkMgr; class p3IdService; // Temp tweak to test grouter -class p3MsgService: public p3Service, public p3Config, public pqiServiceMonitor, public GRouterClientService +struct p3MsgService : + p3Service, p3Config, pqiServiceMonitor, GRouterClientService, + GxsMailsClient { -public: - p3MsgService(p3ServiceControl *sc, p3IdService *id_service); - virtual RsServiceInfo getServiceInfo(); + p3MsgService(p3ServiceControl *sc, p3IdService *id_service, p3GxsMails& gxsMS); + + virtual RsServiceInfo getServiceInfo(); /* External Interface */ bool getMessageSummaries(std::list &msgList); @@ -106,7 +109,9 @@ public: /*** Overloaded from pqiMonitor ***/ virtual void statusChange(const std::list &plist); - int checkOutgoingMessages(); + + /// iterate through the outgoing queue if online, send + int checkOutgoingMessages(); /*** Overloaded from pqiMonitor ***/ /*** overloaded from p3turtle ***/ @@ -130,16 +135,25 @@ public: void setDistantMessagingPermissionFlags(uint32_t flags) ; uint32_t getDistantMessagingPermissionFlags() ; -private: - void sendDistantMsgItem(RsMsgItem *msgitem) ; + /// @see GxsMailsClient::receiveGxsMail(...) + virtual bool receiveGxsMail( const RsGxsMailItem& originalMessage, + const uint8_t* data, uint32_t dataSize ); - // This contains the ongoing tunnel handling contacts. - // The map is indexed by the hash - // - std::map _ongoing_messages ; + /// @see GxsMailsClient::notifySendMailStatus(...) + virtual bool notifySendMailStatus( const RsGxsMailItem& originalMessage, + GxsMailStatus status ); + +private: + void sendDistantMsgItem(RsMsgItem *msgitem); + + /** This contains the ongoing tunnel handling contacts. + * The map is indexed by the hash */ + std::map _ongoing_messages; + + std::map gxsOngoingMessages; + RsMutex gxsOngoingMutex; // Overloaded from GRouterClientService - virtual bool acceptDataFromPeer(const RsGxsId& gxs_id) ; virtual void receiveGRouterData(const RsGxsId& destination_key,const RsGxsId& signing_key, GRouterServiceId &client_id, uint8_t *data, uint32_t data_size) ; virtual void notifyDataStatus(const GRouterMsgPropagationId& msg_id,const RsGxsId& signer_id,uint32_t data_status) ; @@ -194,8 +208,9 @@ private: std::map mTags; std::map mMsgTags; - uint32_t mMsgUniqueId; - std::map mRecentlyReceivedDistantMessageHashes; + uint32_t mMsgUniqueId; + std::map mRecentlyReceivedMessageHashes; + RsMutex recentlyReceivedMutex; // used delete msgSrcIds after config save std::map mSrcIds; @@ -211,6 +226,8 @@ private: bool mDistantMessagingEnabled ; uint32_t mDistantMessagePermissions ; bool mShouldEnableDistantMessaging ; + + p3GxsMails& gxsMailService; }; #endif // MESSAGE_SERVICE_HEADER From 77c430d553bbb83513a8c7c996da3f09f58b6edc Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Wed, 22 Feb 2017 13:34:36 +0100 Subject: [PATCH 14/35] Use unordered_multimap for ingoingQueue This will avoid the possibility for a malicious node to cause a memory leak and smash items in incoming queue of others nodes --- libretroshare/src/services/p3gxsmails.cpp | 25 ++++++++++++----------- libretroshare/src/services/p3gxsmails.h | 4 +++- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/libretroshare/src/services/p3gxsmails.cpp b/libretroshare/src/services/p3gxsmails.cpp index ae7f3755d..ab0baa493 100644 --- a/libretroshare/src/services/p3gxsmails.cpp +++ b/libretroshare/src/services/p3gxsmails.cpp @@ -568,19 +568,20 @@ void p3GxsMails::processOutgoingRecord(OutgoingRecord& pr) case GxsMailStatus::PENDING_RECEIPT_RECEIVE: { RS_STACK_MUTEX(ingoingMutex); - auto it = ingoingQueue.find(pr.mailItem.mailId); - if (it == ingoingQueue.end()) break; - RsGxsMailPresignedReceipt* rt = - dynamic_cast(it->second); - if( !rt || !idService.isOwnId(rt->meta.mAuthorId) ) break; - - ingoingQueue.erase(it); delete rt; - pr.status = GxsMailStatus::RECEIPT_RECEIVED; - // TODO: Malicious adversary could forge messages with same mailId and - // could end up overriding the legit receipt in ingoingQueue, and - // causing also a memleak(using unordered_multimap for ingoingQueue - // may fix this?) + auto range = ingoingQueue.equal_range(pr.mailItem.mailId); + for( auto it = range.first; it != range.second; ++it) + { + RsGxsMailPresignedReceipt* rt = + dynamic_cast(it->second); + if(rt && idService.isOwnId(rt->meta.mAuthorId)) + { + ingoingQueue.erase(it); delete rt; + pr.status = GxsMailStatus::RECEIPT_RECEIVED; + break; + } + } // TODO: Resend message if older then treshold + break; } case GxsMailStatus::RECEIPT_RECEIVED: break; diff --git a/libretroshare/src/services/p3gxsmails.h b/libretroshare/src/services/p3gxsmails.h index 9184f7074..521b1eb67 100644 --- a/libretroshare/src/services/p3gxsmails.h +++ b/libretroshare/src/services/p3gxsmails.h @@ -18,6 +18,8 @@ */ #include +#include +#include #include "retroshare/rsgxsifacetypes.h" // For RsGxsId, RsGxsCircleId #include "gxs/gxstokenqueue.h" // For GxsTokenQueue @@ -184,7 +186,7 @@ private: RsMutex outgoingMutex; void processOutgoingRecord(OutgoingRecord& r); - typedef std::map inMap; + typedef std::unordered_multimap inMap; inMap ingoingQueue; RsMutex ingoingMutex; From f9b0063704d08f2d8403a729a86c0f3bd3f54d62 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Wed, 22 Feb 2017 14:46:40 +0100 Subject: [PATCH 15/35] Improve incoming receipts handling --- libretroshare/src/services/p3gxsmails.cpp | 80 +++++++++++++++++------ libretroshare/src/services/p3gxsmails.h | 2 +- 2 files changed, 60 insertions(+), 22 deletions(-) diff --git a/libretroshare/src/services/p3gxsmails.cpp b/libretroshare/src/services/p3gxsmails.cpp index ab0baa493..41aa616f1 100644 --- a/libretroshare/src/services/p3gxsmails.cpp +++ b/libretroshare/src/services/p3gxsmails.cpp @@ -115,7 +115,7 @@ void p3GxsMails::handleResponse(uint32_t token, uint32_t req_type) { /* This is true only at first run when we haven't received mail * distribuition groups from friends - * TODO: We should check if we have some connected firend too, to + * TODO: We should check if we have some connected friend too, to * avoid to create yet another never used mail distribution group. */ @@ -211,29 +211,67 @@ void p3GxsMails::service_tick() RS_STACK_MUTEX(ingoingMutex); for( auto it = ingoingQueue.begin(); it != ingoingQueue.end(); ) { - if( it->second->PacketSubType() != GXS_MAIL_SUBTYPE_MAIL ) - { ++it; continue; } - - RsGxsMailItem* msg = dynamic_cast(it->second); - if(!msg) + switch (it->second->PacketSubType()) { - std::cout << "p3GxsMails::service_tick() GXS_MAIL_SUBTYPE_MAIL" - << "dynamic_cast failed, something really wrong is " - << "happening!" << std::endl; - ++it; continue; + case GXS_MAIL_SUBTYPE_MAIL: + { + RsGxsMailItem* msg = dynamic_cast(it->second); + if(!msg) + { + std::cerr << "p3GxsMails::service_tick() (EE) " + << "GXS_MAIL_SUBTYPE_MAIL dynamic_cast failed, " + << "something really wrong is happening!" + << std::endl; + } + else + { + std::cout << "p3GxsMails::service_tick() " + << "GXS_MAIL_SUBTYPE_MAIL handling: " + << msg->meta.mMsgId + << " with cryptoType: " + << static_cast(msg->cryptoType) + << " recipientHint: " << msg->recipientsHint + << " mailId: "<< msg->mailId + << " payload.size(): " << msg->payload.size() + << std::endl; + handleEcryptedMail(msg); + } + break; + } + case GXS_MAIL_SUBTYPE_RECEIPT: + { + RsGxsMailPresignedReceipt* rcpt = + dynamic_cast(it->second); + if(!rcpt) + { + std::cerr << "p3GxsMails::service_tick() (EE) " + << "GXS_MAIL_SUBTYPE_RECEIPT dynamic_cast failed," + << " something really wrong is happening!" + << std::endl; + } + else if(idService.isOwnId(rcpt->meta.mAuthorId)) + { + /* It is a receipt for a mail sent by this node live it in + * ingoingQueue so processOutgoingRecord(...) will take care + * of it at next tick */ + ++it; + continue; + } + else + { + /* TODO: It is a receipt for a message sent by someone else + * we can delete original mail from our GXS DB without + * waiting for GXS_STORAGE_PERIOD */ + } + break; + } + default: + std::cerr << "p3GxsMails::service_tick() (EE) got something " + << "really unknown into ingoingQueue!!" << std::endl; + break; } - std::cout << "p3GxsMails::service_tick() GXS_MAIL_SUBTYPE_MAIL " - << "handling: " << msg->meta.mMsgId - << " with cryptoType: " - << static_cast(msg->cryptoType) - << " recipientHint: " << msg->recipientsHint - << " mailId: "<< msg->mailId - << " payload.size(): " << msg->payload.size() - << std::endl; - - handleEcryptedMail(msg); - it = ingoingQueue.erase(it); delete msg; + delete it->second; it = ingoingQueue.erase(it); } } } diff --git a/libretroshare/src/services/p3gxsmails.h b/libretroshare/src/services/p3gxsmails.h index 521b1eb67..072a07a93 100644 --- a/libretroshare/src/services/p3gxsmails.h +++ b/libretroshare/src/services/p3gxsmails.h @@ -65,7 +65,7 @@ struct GxsMailsClient GxsMailStatus status ) = 0; }; -struct p3GxsMails : RsGenExchange, GxsTokenQueue +struct p3GxsMails : RsGenExchange, GxsTokenQueue // TODO: p3Config { p3GxsMails( RsGeneralDataService* gds, RsNetworkExchangeService* nes, p3IdService& identities ) : From 828792f2b56d54ca09d692e45746cf5420fde097 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Thu, 23 Feb 2017 13:20:07 +0100 Subject: [PATCH 16/35] p3Config improved coding style --- libretroshare/src/pqi/p3cfgmgr.h | 73 +++++++++++++++----------------- 1 file changed, 35 insertions(+), 38 deletions(-) diff --git a/libretroshare/src/pqi/p3cfgmgr.h b/libretroshare/src/pqi/p3cfgmgr.h index e328652a6..b3ffc8fe3 100644 --- a/libretroshare/src/pqi/p3cfgmgr.h +++ b/libretroshare/src/pqi/p3cfgmgr.h @@ -144,7 +144,6 @@ void setHash(const RsFileHash& h); * Class data is protected by mutex's so that anyone can call these * functions, at any time. */ - class p3ConfigMgr { public: @@ -177,7 +176,7 @@ class p3ConfigMgr */ void addConfiguration(std::string file, pqiConfig *conf); - /* saves config, and disables further saving + /** saves config, and disables further saving * used for exiting the system */ void completeConfiguration(); @@ -209,55 +208,53 @@ class p3ConfigMgr /***************************************************************************************************/ -//! abstract class for configuration saving, aimed at rs services that uses RsItem config data -/*! - * The aim of this class is to provide a way for rs services and object to save particular - * configurations an items (and load them up as well). +/** + * @brief Abstract class for configuration saving. + * Aimed at rs services that uses RsItem config data, provide a way for RS + * services to save and load particular configurations as items. */ -class p3Config: public pqiConfig +struct p3Config : pqiConfig { - public: - p3Config(); -virtual bool loadConfiguration(RsFileHash &loadHash); -virtual bool saveConfiguration(); + virtual bool loadConfiguration(RsFileHash &loadHash); + virtual bool saveConfiguration(); +protected: - protected: + /// Key Functions to be overloaded for Full Configuration + virtual RsSerialiser *setupSerialiser() = 0; - /* Key Functions to be overloaded for Full Configuration */ -virtual RsSerialiser *setupSerialiser() = 0; + /** + * saves list of derived object + * @param cleanup this inform you if you need to call saveDone() to + * unlock/allow access to resources pointed to by handles (list) + * returned by function: thus false, call saveDone after returned list + * finished with and vice versa + * @return list of config items derived object wants to saves + */ + virtual bool saveList(bool &cleanup, std::list&) = 0; -/** - * saves list of derived object - * @param cleanup this inform you if you need to call saveDone() to unlock/allow - * access to resources pointed to by handles (list) returned by function: thus false, call saveDone after returned list finished with - * and vice versa - * @return list of config items derived object wants to saves - */ -virtual bool saveList(bool &cleanup, std::list&) = 0; + /** + * loads up list of configs items for derived object + * @param load list of config items to load up + */ + virtual bool loadList(std::list& load) = 0; -/** - * loads up list of configs items for derived object - * @param load list of config items to load up - */ -virtual bool loadList(std::list& load) = 0; - -/** - * callback for mutex unlocking - * in derived classes (should only be needed if cleanup = false) - */ -virtual void saveDone() { return; } + /** + * callback for mutex unlocking + * in derived classes (should only be needed if cleanup = false) + */ + virtual void saveDone() {} private: -bool loadConfig(); -bool saveConfig(); + bool loadConfig(); + bool saveConfig(); -bool loadAttempt(const std::string&,const std::string&, std::list& load); - -}; /* end of p3Config */ + bool loadAttempt( const std::string&, const std::string&, + std::list& load ); +}; // end of p3Config class p3GeneralConfig: public p3Config From 748e75d3e1bf399f8254708f731b2851700ead5d Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Sat, 25 Feb 2017 23:09:46 +0100 Subject: [PATCH 17/35] Fix pqiSSLstore::encryptedSendItems empty list RsTemporaryMemory was complaining of being initialized with size 0 in case of empty list was passed to the method, this is a legitimate use case when one want have an empty list as state, so in this case pass 1 as argument to RsTemporaryMemory constructor --- libretroshare/src/pqi/pqistore.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libretroshare/src/pqi/pqistore.cc b/libretroshare/src/pqi/pqistore.cc index ca6d23820..c94917de8 100644 --- a/libretroshare/src/pqi/pqistore.cc +++ b/libretroshare/src/pqi/pqistore.cc @@ -394,10 +394,9 @@ bool pqiSSLstore::encryptedSendItems(const std::list& rsItemList) uint32_t offset = 0; for(it = rsItemList.begin(); it != rsItemList.end(); ++it) - if(*it != NULL) - sizeItems += rsSerialiser->size(*it); + if(*it != NULL) sizeItems += rsSerialiser->size(*it); - RsTemporaryMemory data(sizeItems) ; + RsTemporaryMemory data( sizeItems ? sizeItems : 1 ); for(it = rsItemList.begin(); it != rsItemList.end(); ++it) if(*it != NULL) From 379fb97062025a6cbd19acbde8b5ba5fcebdcdb8 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Sun, 26 Feb 2017 00:46:02 +0100 Subject: [PATCH 18/35] p3GxsMails queues persistents accross RS sessions RsServer properly handle deletion (childs are not yet) p3GxsMails properly handle deletion RsControl::instance() use proper static initialization p3GxsMails register configuration files at right time RsGxsMailBaseItem take in account offset in header pointer RsGxsMailSerializer use C++11 safe enum class for items types RsGxsMailItem take in account offset in header pointer RsGxsMailItem::deserialize(...) properly calculate final offset p3GxsMails::handleResponse(...) delete group items after usage move ex inner struct OutgoingRecord to gxs mail items header p3MsgService::saveList removed unused variable p3MsgService::notifyDataStatus(...) take in account multiple backends p3MsgService::receiveGxsMail(...) take in account multiple backends p3MsgService::receiveGRouterData(...) take in account multiple backends Added prersistence to p3MsgService::gxsOngoingMessages --- libretroshare/src/retroshare/rsiface.h | 7 +- libretroshare/src/rsserver/p3face-server.cc | 2 +- libretroshare/src/rsserver/p3face.h | 1 + libretroshare/src/rsserver/rsinit.cc | 23 ++- .../src/serialiser/rsgxsmailitems.cc | 139 ++++++++++++- libretroshare/src/serialiser/rsgxsmailitems.h | 109 ++++++++-- libretroshare/src/services/p3gxsmails.cpp | 150 ++++++++++++-- libretroshare/src/services/p3gxsmails.h | 110 +++++----- libretroshare/src/services/p3msgservice.cc | 194 ++++++++++-------- libretroshare/src/services/p3msgservice.h | 1 + 10 files changed, 535 insertions(+), 201 deletions(-) diff --git a/libretroshare/src/retroshare/rsiface.h b/libretroshare/src/retroshare/rsiface.h index 74ec041f0..2eb905e3a 100644 --- a/libretroshare/src/retroshare/rsiface.h +++ b/libretroshare/src/retroshare/rsiface.h @@ -53,9 +53,10 @@ int InitRetroShare(int argc, char **argv, RsInit *config); class RsControl /* The Main Interface Class - for controlling the server */ { - public: - static RsControl *instance() ; - static void earlyInitNotificationSystem() { instance() ; } +public: + /// TODO: This should return a reference instead of a pointer! + static RsControl *instance(); + static void earlyInitNotificationSystem() { instance(); } /* Real Startup Fn */ virtual int StartupRetroShare() = 0; diff --git a/libretroshare/src/rsserver/p3face-server.cc b/libretroshare/src/rsserver/p3face-server.cc index 037ef3a44..28b223341 100644 --- a/libretroshare/src/rsserver/p3face-server.cc +++ b/libretroshare/src/rsserver/p3face-server.cc @@ -122,7 +122,7 @@ RsServer::RsServer() RsServer::~RsServer() { - return; + delete mGxsMails; } /* General Internal Helper Functions diff --git a/libretroshare/src/rsserver/p3face.h b/libretroshare/src/rsserver/p3face.h index 3d88e22fb..de30f908d 100644 --- a/libretroshare/src/rsserver/p3face.h +++ b/libretroshare/src/rsserver/p3face.h @@ -179,6 +179,7 @@ class RsServer: public RsControl, public RsTickingThread // p3GxsForums *mGxsForums; // p3GxsChannels *mGxsChannels; // p3Wire *mWire; + p3GxsMails* mGxsMails; /* Config */ p3ConfigMgr *mConfigMgr; diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index b33dcef1d..1ec7a4b54 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -944,14 +944,11 @@ RsGRouter *rsGRouter = NULL ; RsControl *RsControl::instance() { - static RsServer *rsicontrol = NULL ; - - if(rsicontrol == NULL) - rsicontrol = new RsServer(); - - return rsicontrol; + static RsServer rsicontrol; + return &rsicontrol; } + /* * The Real RetroShare Startup Function. */ @@ -1491,14 +1488,13 @@ int RsServer::StartupRetroShare() RsGeneralDataService* gxsmail_ds = new RsDataService( currGxsDir + "/", "gxsmails_db", RS_SERVICE_TYPE_GXS_MAIL, NULL, rsInitConfig->gxs_passwd ); - p3GxsMails* mGxsMails = new p3GxsMails(gxsmail_ds, NULL, *mGxsIdService); + mGxsMails = new p3GxsMails(gxsmail_ds, NULL, *mGxsIdService); RsGxsNetService* gxsmails_ns = new RsGxsNetService( RS_SERVICE_TYPE_GXS_MAIL, gxsmail_ds, nxsMgr, mGxsMails, mGxsMails->getServiceInfo(), mReputations, mGxsCircles, mGxsIdService, pgpAuxUtils); mGxsMails->setNetworkExchangeService(gxsmails_ns); pqih->addService(gxsmails_ns, true); - mConfigMgr->addConfiguration("gxs_mail.cfg", gxsmails_ns); TestGxsMailClientService* tgms = new TestGxsMailClientService(*mGxsMails, *mGxsIdService); @@ -1673,13 +1669,20 @@ int RsServer::StartupRetroShare() #ifdef ENABLE_GROUTER mConfigMgr->addConfiguration("grouter.cfg", gr); #endif - mConfigMgr->addConfiguration("p3identity.cfg", mGxsIdService); #ifdef RS_USE_BITDHT - mConfigMgr->addConfiguration("bitdht.cfg", mBitDht); + mConfigMgr->addConfiguration("bitdht.cfg", mBitDht); #endif #ifdef RS_ENABLE_GXS + +# ifdef RS_GXS_MAIL + mConfigMgr->addConfiguration("gxs_mail_ns.cfg", gxsmails_ns); + mConfigMgr->addConfiguration("gxs_mail.cfg", mGxsMails); +# endif + + mConfigMgr->addConfiguration("p3identity.cfg", mGxsIdService); + mConfigMgr->addConfiguration("identity.cfg", gxsid_ns); mConfigMgr->addConfiguration("gxsforums.cfg", gxsforums_ns); mConfigMgr->addConfiguration("gxschannels.cfg", gxschannels_ns); diff --git a/libretroshare/src/serialiser/rsgxsmailitems.cc b/libretroshare/src/serialiser/rsgxsmailitems.cc index f1a659d43..6aca99b37 100644 --- a/libretroshare/src/serialiser/rsgxsmailitems.cc +++ b/libretroshare/src/serialiser/rsgxsmailitems.cc @@ -24,7 +24,7 @@ const RsGxsId RsGxsMailItem::allRecipientsHint("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF bool RsGxsMailBaseItem::serialize(uint8_t* data, uint32_t size, uint32_t& offset) const { - bool ok = setRsItemHeader(data, size, PacketId(), size); + bool ok = setRsItemHeader(data+offset, size, PacketId(), size); ok = ok && (offset += 8); // Take header in account ok = ok && setRawUInt64(data, size, &offset, mailId); return ok; @@ -33,9 +33,11 @@ bool RsGxsMailBaseItem::serialize(uint8_t* data, uint32_t size, bool RsGxsMailBaseItem::deserialize(const uint8_t* data, uint32_t& size, uint32_t& offset) { - void* dataPtr = reinterpret_cast(const_cast(data)); - uint32_t rssize = getRsItemSize(dataPtr); + void* hdrPtr = const_cast(data+offset); + uint32_t rssize = getRsItemSize(hdrPtr); uint32_t roffset = offset + 8; // Take header in account + + void* dataPtr = const_cast(data); bool ok = rssize <= size; ok = ok && getRawUInt64(dataPtr, rssize, &roffset, &mailId); if(ok) { size = rssize; offset = roffset; } @@ -57,27 +59,34 @@ bool RsGxsMailSerializer::serialise(RsItem* item, void* data, uint32_t* size) } uint8_t* dataPtr = reinterpret_cast(data); - bool ok = true; - switch(item->PacketSubType()) + bool ok = false; + switch(static_cast(item->PacketSubType())) { - case GXS_MAIL_SUBTYPE_MAIL: + case GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_MAIL: { uint32_t offset = 0; RsGxsMailItem* i = dynamic_cast(item); - ok = i->serialize(dataPtr, itemSize, offset); + ok = i && i->serialize(dataPtr, itemSize, offset); break; } - case GXS_MAIL_SUBTYPE_RECEIPT: + case GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_RECEIPT: { RsGxsMailPresignedReceipt* i = dynamic_cast(item); uint32_t offset = 0; - ok = i->serialize(dataPtr, itemSize, offset); + ok = i && i->serialize(dataPtr, itemSize, offset); break; } - case GXS_MAIL_SUBTYPE_GROUP: + case GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_GROUP: ok = setRsItemHeader(data, itemSize, item->PacketId(), itemSize); break; + case GxsMailItemsSubtypes::OUTGOING_RECORD_ITEM: + { + uint32_t offset = 0; + OutgoingRecord* i = dynamic_cast(item); + ok = i && i->serialize(dataPtr, itemSize, offset); + break; + } default: ok = false; break; } @@ -91,3 +100,113 @@ bool RsGxsMailSerializer::serialise(RsItem* item, void* data, uint32_t* size) return false; } +OutgoingRecord::OutgoingRecord( RsGxsId rec, GxsMailSubServices cs, + const uint8_t* data, uint32_t size ) : + RsItem( RS_PKT_VERSION_SERVICE, RS_SERVICE_TYPE_GXS_MAIL, + static_cast(GxsMailItemsSubtypes::OUTGOING_RECORD_ITEM) ), + status(GxsMailStatus::PENDING_PROCESSING), recipient(rec), + clientService(cs) +{ + mailData.resize(size); + memcpy(&mailData[0], data, size); +} + +void OutgoingRecord::clear() +{ + status = GxsMailStatus::UNKNOWN; + recipient.clear(); + mailItem.clear(); + mailData.clear(); + clientService = GxsMailSubServices::UNKNOWN; + presignedReceipt.clear(); +} + +std::ostream& OutgoingRecord::print(std::ostream& out, uint16_t) +{ return out << "TODO: OutgoingRecordItem::print(...)"; } + +OutgoingRecord::OutgoingRecord() : + RsItem( RS_PKT_VERSION_SERVICE, RS_SERVICE_TYPE_GXS_MAIL, + static_cast(GxsMailItemsSubtypes::OUTGOING_RECORD_ITEM) ) +{ clear();} + +uint32_t OutgoingRecord::size() const +{ + return 8 + // Header + 1 + // status + recipient.serial_size() + + mailItem.size() + + 4 + // sizeof(mailData.size()) + mailData.size() + + 2 + // clientService + presignedReceipt.serial_size(); +} + +bool OutgoingRecord::serialize( uint8_t* data, uint32_t size, + uint32_t& offset) const +{ + bool ok = true; + + ok = ok && setRsItemHeader(data+offset, size, PacketId(), size) + && (offset += 8); // Take header in account + + ok = ok && setRawUInt8(data, size, &offset, static_cast(status)); + + ok = ok && recipient.serialise(data, size, offset); + + uint32_t tmpOffset = 0; + uint32_t tmpSize = mailItem.size(); + ok = ok && mailItem.serialize(data+offset, tmpSize, tmpOffset) + && (offset += tmpOffset); + + uint32_t dSize = mailData.size(); + ok = ok && setRawUInt32(data, size, &offset, dSize) + && memcpy(data+offset, &mailData[0], dSize) && (offset += dSize); + + ok = ok && setRawUInt16( data, size, &offset, + static_cast(clientService) ); + + dSize = presignedReceipt.serial_size(); + ok = ok && presignedReceipt.serialise(data+offset, dSize) + && (offset += dSize); + + return ok; +} + +bool OutgoingRecord::deserialize( + const uint8_t* data, uint32_t& size, uint32_t& offset) +{ + bool ok = true; + + void* dataPtr = const_cast(data); + offset += 8; // Header + + uint8_t tmpStatus = 0; + ok = ok && getRawUInt8(dataPtr, size, &offset, &tmpStatus); + status = static_cast(tmpStatus); + + uint32_t tmpSize = size; + ok = ok && recipient.deserialise(dataPtr, tmpSize, offset); + + void* hdrPtr = const_cast(data+offset); + tmpSize = getRsItemSize(hdrPtr); + + uint32_t tmpOffset = 0; + ok = ok && mailItem.deserialize(static_cast(hdrPtr), tmpSize, tmpOffset); + ok = ok && (offset += tmpOffset); + + tmpSize = size; + ok = getRawUInt32(dataPtr, tmpSize, &offset, &tmpSize); + ok = ok && (tmpSize+offset < size); + ok = ok && (mailData.resize(tmpSize), memcpy(&mailData[0], data, tmpSize)); + ok = ok && (offset += tmpSize); + + uint16_t cs = 0; + ok = ok && getRawUInt16(dataPtr, offset+2, &offset, &cs); + clientService = static_cast(cs); + + tmpSize = size; + ok = ok && presignedReceipt.deserialize(data, tmpSize, offset); + + return ok; +} + diff --git a/libretroshare/src/serialiser/rsgxsmailitems.h b/libretroshare/src/serialiser/rsgxsmailitems.h index 4ec0094df..61545fbb5 100644 --- a/libretroshare/src/serialiser/rsgxsmailitems.h +++ b/libretroshare/src/serialiser/rsgxsmailitems.h @@ -26,12 +26,21 @@ #include "retroshare/rsgxscircles.h" // For: GXS_CIRCLE_TYPE_PUBLIC #include "services/p3idservice.h" +/// Subservices identifiers (like port for TCP) +enum class GxsMailSubServices : uint16_t +{ + UNKNOWN = 0, + TEST_SERVICE = 1, + P3_MSG_SERVICE = 2 +}; + /// Values must fit into uint8_t -enum GxsMailItemsSubtypes +enum class GxsMailItemsSubtypes : uint8_t { GXS_MAIL_SUBTYPE_MAIL = 1, GXS_MAIL_SUBTYPE_RECEIPT = 2, - GXS_MAIL_SUBTYPE_GROUP = 3 + GXS_MAIL_SUBTYPE_GROUP = 3, + OUTGOING_RECORD_ITEM = 4 }; typedef uint64_t RsGxsMailId; @@ -67,7 +76,8 @@ struct RsGxsMailBaseItem : RsGxsMsgItem struct RsGxsMailPresignedReceipt : RsGxsMailBaseItem { - RsGxsMailPresignedReceipt() : RsGxsMailBaseItem(GXS_MAIL_SUBTYPE_RECEIPT) {} + RsGxsMailPresignedReceipt() : + RsGxsMailBaseItem(GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_RECEIPT) {} }; enum class RsGxsMailEncryptionMode : uint8_t @@ -79,7 +89,8 @@ enum class RsGxsMailEncryptionMode : uint8_t struct RsGxsMailItem : RsGxsMailBaseItem { - RsGxsMailItem() : RsGxsMailBaseItem(GXS_MAIL_SUBTYPE_MAIL), + RsGxsMailItem() : + RsGxsMailBaseItem(GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_MAIL), cryptoType(RsGxsMailEncryptionMode::UNDEFINED_ENCRYPTION) {} RsGxsMailEncryptionMode cryptoType; @@ -158,17 +169,21 @@ struct RsGxsMailItem : RsGxsMailBaseItem } bool deserialize(const uint8_t* data, uint32_t& size, uint32_t& offset) { - void* dataPtr = reinterpret_cast(const_cast(data)); - uint32_t rssize = getRsItemSize(dataPtr); + void* sizePtr = const_cast(data+offset); + uint32_t rssize = getRsItemSize(sizePtr); + uint32_t roffset = offset; bool ok = rssize <= size && size < MAX_SIZE; ok = ok && RsGxsMailBaseItem::deserialize(data, rssize, roffset); + + void* dataPtr = const_cast(data); uint8_t crType; ok = ok && getRawUInt8(dataPtr, rssize, &roffset, &crType); cryptoType = static_cast(crType); ok = ok && recipientsHint.deserialise(dataPtr, rssize, roffset); uint32_t psz = rssize - roffset; ok = ok && (payload.resize(psz), memcpy(&payload[0], data+roffset, psz)); + ok = ok && (roffset += psz); if(ok) { size = rssize; offset = roffset; } else size = 0; return ok; @@ -188,7 +203,9 @@ struct RsGxsMailItem : RsGxsMailBaseItem struct RsGxsMailGroupItem : RsGxsGrpItem { RsGxsMailGroupItem() : - RsGxsGrpItem(RS_SERVICE_TYPE_GXS_MAIL, GXS_MAIL_SUBTYPE_GROUP) + RsGxsGrpItem( RS_SERVICE_TYPE_GXS_MAIL, + static_cast( + GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_GROUP) ) { meta.mGroupFlags = GXS_SERV::FLAG_PRIVACY_PUBLIC; meta.mGroupName = "Mail"; @@ -200,6 +217,54 @@ struct RsGxsMailGroupItem : RsGxsGrpItem { return out; } }; +enum class GxsMailStatus : uint8_t +{ + UNKNOWN = 0, + PENDING_PROCESSING, + PENDING_PREFERRED_GROUP, + PENDING_RECEIPT_CREATE, + PENDING_RECEIPT_SIGNATURE, + PENDING_SERIALIZATION, + PENDING_PAYLOAD_CREATE, + PENDING_PAYLOAD_ENCRYPT, + PENDING_PUBLISH, + /** This will be useful so the user can know if the mail reached at least + * some friend node, in case of internet connection interruption */ + //PENDING_TRANSFER, + PENDING_RECEIPT_RECEIVE, + /// Records with status >= RECEIPT_RECEIVED get deleted + RECEIPT_RECEIVED, + FAILED_RECEIPT_SIGNATURE = 240, + FAILED_ENCRYPTION +}; + +class RsGxsMailSerializer; +struct OutgoingRecord : RsItem +{ + OutgoingRecord( RsGxsId rec, GxsMailSubServices cs, + const uint8_t* data, uint32_t size ); + + GxsMailStatus status; + RsGxsId recipient; + /// Don't use a pointer would be invalid after publish + RsGxsMailItem mailItem; + std::vector mailData; + GxsMailSubServices clientService; + RsNxsMailPresignedReceipt presignedReceipt; + + uint32_t size() const; + bool serialize(uint8_t* data, uint32_t size, uint32_t& offset) const; + bool deserialize(const uint8_t* data, uint32_t& size, uint32_t& offset); + + virtual void clear(); + virtual std::ostream &print(std::ostream &out, uint16_t indent = 0); + +private: + friend class RsGxsMailSerializer; + OutgoingRecord(); +}; + + struct RsGxsMailSerializer : RsSerialType { RsGxsMailSerializer() : RsSerialType( RS_PKT_VERSION_SERVICE, @@ -209,17 +274,23 @@ struct RsGxsMailSerializer : RsSerialType uint32_t size(RsItem* item) { uint32_t sz = 0; - switch(item->PacketSubType()) + switch(static_cast(item->PacketSubType())) { - case GXS_MAIL_SUBTYPE_MAIL: + case GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_MAIL: { RsGxsMailItem* i = dynamic_cast(item); if(i) sz = i->size(); break; } - case GXS_MAIL_SUBTYPE_RECEIPT: + case GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_RECEIPT: sz = RsGxsMailPresignedReceipt::size(); break; - case GXS_MAIL_SUBTYPE_GROUP: sz = 8; break; + case GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_GROUP: sz = 8; break; + case GxsMailItemsSubtypes::OUTGOING_RECORD_ITEM: + { + OutgoingRecord* ci = dynamic_cast(item); + if(ci) sz = ci->size(); + break; + } default: break; } @@ -248,9 +319,9 @@ struct RsGxsMailSerializer : RsSerialType bool ok = true; RsItem* ret = NULL; - switch (getRsItemSubType(rstype)) + switch (static_cast(getRsItemSubType(rstype))) { - case GXS_MAIL_SUBTYPE_MAIL: + case GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_MAIL: { RsGxsMailItem* i = new RsGxsMailItem(); uint32_t offset = 0; @@ -258,7 +329,7 @@ struct RsGxsMailSerializer : RsSerialType ret = i; break; } - case GXS_MAIL_SUBTYPE_RECEIPT: + case GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_RECEIPT: { RsGxsMailPresignedReceipt* i = new RsGxsMailPresignedReceipt(); uint32_t offset = 0; @@ -266,11 +337,19 @@ struct RsGxsMailSerializer : RsSerialType ret = i; break; } - case GXS_MAIL_SUBTYPE_GROUP: + case GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_GROUP: { ret = new RsGxsMailGroupItem(); break; } + case GxsMailItemsSubtypes::OUTGOING_RECORD_ITEM: + { + OutgoingRecord* i = new OutgoingRecord(); + uint32_t offset = 0; + ok = ok && i->deserialize(dataPtr, *size, offset); + ret = i; + break; + } default: ok = false; break; diff --git a/libretroshare/src/services/p3gxsmails.cpp b/libretroshare/src/services/p3gxsmails.cpp index 41aa616f1..55667cf9a 100644 --- a/libretroshare/src/services/p3gxsmails.cpp +++ b/libretroshare/src/services/p3gxsmails.cpp @@ -20,8 +20,18 @@ #include "util/stacktrace.h" +p3GxsMails::~p3GxsMails() +{ + p3Config::saveConfiguration(); + + { + RS_STACK_MUTEX(ingoingMutex); + for ( auto& kv : ingoingQueue ) delete kv.second; + } +} + bool p3GxsMails::sendMail( RsGxsMailId& mailId, - GxsMailsClient::GxsMailSubServices service, + GxsMailSubServices service, const RsGxsId& own_gxsid, const RsGxsId& recipient, const uint8_t* data, uint32_t size, RsGxsMailEncryptionMode cm ) @@ -69,13 +79,12 @@ bool p3GxsMails::querySendMailStatus(RsGxsMailId mailId, GxsMailStatus& st) } void p3GxsMails::registerGxsMailsClient( - GxsMailsClient::GxsMailSubServices serviceType, GxsMailsClient* service) + GxsMailSubServices serviceType, GxsMailsClient* service) { RS_STACK_MUTEX(servClientsMutex); servClients[serviceType] = service; } - void p3GxsMails::handleResponse(uint32_t token, uint32_t req_type) { std::cout << "p3GxsMails::handleResponse(" << token << ", " << req_type @@ -87,8 +96,7 @@ void p3GxsMails::handleResponse(uint32_t token, uint32_t req_type) std::vector groups; getGroupData(token, groups); - for( std::vector::iterator it = groups.begin(); - it != groups.end(); ++it ) + for( auto grp : groups ) { /* For each group check if it is better candidate then * preferredGroupId, if it is supplant it and subscribe if it is not @@ -98,17 +106,39 @@ void p3GxsMails::handleResponse(uint32_t token, uint32_t req_type) * unsubscribe. */ - const RsGroupMetaData& meta = (*it)->meta; + const RsGroupMetaData& meta = grp->meta; bool subscribed = IS_GROUP_SUBSCRIBED(meta.mSubscribeFlags); bool old = olderThen( meta.mLastPost, UNUSED_GROUP_UNSUBSCRIBE_INTERVAL ); bool supersede = supersedePreferredGroup(meta.mGroupId); uint32_t token; - if( !subscribed && ( !old || supersede )) + bool shoudlSubscribe = !subscribed && ( !old || supersede ); + bool shoudlUnSubscribe = subscribed && old + && meta.mGroupId != preferredGroupId; + + if(shoudlSubscribe) subscribeToGroup(token, meta.mGroupId, true); - else if( subscribed && old ) + else if(shoudlUnSubscribe) subscribeToGroup(token, meta.mGroupId, false); + +#ifdef GXS_MAIL_GRP_DEBUG + char buff[30]; + struct tm* timeinfo; + timeinfo = localtime(&meta.mLastPost); + strftime(buff, sizeof(buff), "%Y %b %d %H:%M", timeinfo); + + std::cout << "p3GxsMails::handleResponse(...) GROUPS_LIST " + << "meta.mGroupId: " << meta.mGroupId + << " meta.mLastPost: " << buff + << " subscribed: " << subscribed + << " old: " << old + << " shoudlSubscribe: " << shoudlSubscribe + << " shoudlUnSubscribe: " << shoudlUnSubscribe + << std::endl; +#endif // GXS_MAIL_GRP_DEBUG + + delete grp; } if(preferredGroupId.isNull()) @@ -150,10 +180,10 @@ void p3GxsMails::handleResponse(uint32_t token, uint32_t req_type) for( vT::const_iterator mIt = mv.begin(); mIt != mv.end(); ++mIt ) { RsGxsMsgItem* gIt = *mIt; - switch(gIt->PacketSubType()) + switch(static_cast(gIt->PacketSubType())) { - case GXS_MAIL_SUBTYPE_MAIL: - case GXS_MAIL_SUBTYPE_RECEIPT: + case GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_MAIL: + case GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_RECEIPT: { RsGxsMailBaseItem* mb = dynamic_cast(*mIt); @@ -211,9 +241,10 @@ void p3GxsMails::service_tick() RS_STACK_MUTEX(ingoingMutex); for( auto it = ingoingQueue.begin(); it != ingoingQueue.end(); ) { - switch (it->second->PacketSubType()) + switch(static_cast( + it->second->PacketSubType())) { - case GXS_MAIL_SUBTYPE_MAIL: + case GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_MAIL: { RsGxsMailItem* msg = dynamic_cast(it->second); if(!msg) @@ -238,7 +269,7 @@ void p3GxsMails::service_tick() } break; } - case GXS_MAIL_SUBTYPE_RECEIPT: + case GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_RECEIPT: { RsGxsMailPresignedReceipt* rcpt = dynamic_cast(it->second); @@ -276,9 +307,11 @@ void p3GxsMails::service_tick() } } -RsGenExchange::ServiceCreate_Return p3GxsMails::service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySet& /*keySet*/) +RsGenExchange::ServiceCreate_Return p3GxsMails::service_CreateGroup( + RsGxsGrpItem* grpItem, RsTlvSecurityKeySet& /*keySet*/ ) { - std::cout << "p3GxsMails::service_CreateGroup(...) " << grpItem->meta.mGroupId << std::endl; + std::cout << "p3GxsMails::service_CreateGroup(...) " + << grpItem->meta.mGroupId << std::endl; return SERVICE_CREATE_SUCCESS; } @@ -434,8 +467,7 @@ bool p3GxsMails::dispatchDecryptedMail( const RsGxsMailItem* received_msg, << "happening!" << std::endl; return false; } - GxsMailsClient::GxsMailSubServices rsrvc; - rsrvc = static_cast(csri); + GxsMailSubServices rsrvc = static_cast(csri); RsNxsMailPresignedReceipt* receipt = new RsNxsMailPresignedReceipt(); uint32_t rcptsize = decrypted_data_size; @@ -659,3 +691,85 @@ void p3GxsMails::notifyClientService(const OutgoingRecord& pr) print_stacktrace(); } +RsSerialiser* p3GxsMails::setupSerialiser() +{ + RsSerialiser* rss = new RsSerialiser; + rss->addSerialType(new RsGxsMailSerializer); + return rss; +} + +bool p3GxsMails::saveList(bool &cleanup, std::list& saveList) +{ + std::cout << "p3GxsMails::saveList(...)" << saveList.size() << " " + << ingoingQueue.size() << " " << outgoingQueue.size() + << std::endl; + + outgoingMutex.lock(); + ingoingMutex.lock(); + + for ( auto& kv : outgoingQueue ) saveList.push_back(&kv.second); + for ( auto& kv : ingoingQueue ) saveList.push_back(kv.second); + + std::cout << "p3GxsMails::saveList(...)" << saveList.size() << " " + << ingoingQueue.size() << " " << outgoingQueue.size() + << std::endl; + + cleanup = false; + return true; +} + +void p3GxsMails::saveDone() +{ + outgoingMutex.unlock(); + ingoingMutex.unlock(); +} + +bool p3GxsMails::loadList(std::list&loadList) +{ + std::cout << "p3GxsMails::loadList(...) " << loadList.size() << " " + << ingoingQueue.size() << " " << outgoingQueue.size() + << std::endl; + + for(auto& v : loadList) + switch(static_cast(v->PacketSubType())) + { + case GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_MAIL: + case GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_RECEIPT: + { + RsGxsMailBaseItem* mi = dynamic_cast(v); + if(mi) + { + RS_STACK_MUTEX(ingoingMutex); + ingoingQueue.insert(inMap::value_type(mi->mailId, mi)); + } + break; + } + case GxsMailItemsSubtypes::OUTGOING_RECORD_ITEM: + { + OutgoingRecord* ot = dynamic_cast(v); + if(ot) + { + RS_STACK_MUTEX(outgoingMutex); + outgoingQueue.insert( + prMap::value_type(ot->mailItem.mailId, *ot)); + } + delete v; + break; + } + case GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_GROUP: + default: + std::cerr << "p3GxsMails::loadList(...) (EE) got item with " + << "unhandled type: " + << static_cast(v->PacketSubType()) + << std::endl; + delete v; + break; + } + + std::cout << "p3GxsMails::loadList(...) " << loadList.size() << " " + << ingoingQueue.size() << " " << outgoingQueue.size() + << std::endl; + + return true; +} + diff --git a/libretroshare/src/services/p3gxsmails.h b/libretroshare/src/services/p3gxsmails.h index 072a07a93..a48ca58d7 100644 --- a/libretroshare/src/services/p3gxsmails.h +++ b/libretroshare/src/services/p3gxsmails.h @@ -27,30 +27,9 @@ #include "services/p3idservice.h" // For p3IdService #include "util/rsthreads.h" -enum class GxsMailStatus -{ - PENDING_PROCESSING = 0, - PENDING_PREFERRED_GROUP, - PENDING_RECEIPT_CREATE, - PENDING_RECEIPT_SIGNATURE, - PENDING_SERIALIZATION, - PENDING_PAYLOAD_CREATE, - PENDING_PAYLOAD_ENCRYPT, - PENDING_PUBLISH, - //PENDING_TRANSFER, /// This will be useful so the user can know if the mail reached some friend node, in case of internet connection interruption - PENDING_RECEIPT_RECEIVE, - /// Records with status >= RECEIPT_RECEIVED get deleted - RECEIPT_RECEIVED, - FAILED_RECEIPT_SIGNATURE = 240, - FAILED_ENCRYPTION -}; - struct p3GxsMails; struct GxsMailsClient { - /// Subservices identifiers (like port for TCP) - enum GxsMailSubServices : uint16_t { TEST_SERVICE = 1, P3_MSG_SERVICE = 2 }; - /** * This will be called by p3GxsMails to dispatch mails to the subservice * @param originalMessage message as received from GXS backend (encrypted) @@ -65,7 +44,7 @@ struct GxsMailsClient GxsMailStatus status ) = 0; }; -struct p3GxsMails : RsGenExchange, GxsTokenQueue // TODO: p3Config +struct p3GxsMails : RsGenExchange, GxsTokenQueue, p3Config { p3GxsMails( RsGeneralDataService* gds, RsNetworkExchangeService* nes, p3IdService& identities ) : @@ -76,6 +55,7 @@ struct p3GxsMails : RsGenExchange, GxsTokenQueue // TODO: p3Config servClientsMutex("p3GxsMails client services map mutex"), outgoingMutex("p3GxsMails outgoing queue map mutex"), ingoingMutex("p3GxsMails ingoing queue map mutex") {} + ~p3GxsMails(); /** * Send an email to recipient, in the process author of the email is @@ -86,7 +66,7 @@ struct p3GxsMails : RsGenExchange, GxsTokenQueue // TODO: p3Config * @return true if the mail will be sent, false if not */ bool sendMail( RsGxsMailId& mailId, - GxsMailsClient::GxsMailSubServices service, + GxsMailSubServices service, const RsGxsId& own_gxsid, const RsGxsId& recipient, const uint8_t* data, uint32_t size, RsGxsMailEncryptionMode cm = RsGxsMailEncryptionMode::RSA @@ -103,25 +83,13 @@ struct p3GxsMails : RsGenExchange, GxsTokenQueue // TODO: p3Config * GxsMailsClient::receiveGxsMail(...) callback * This method is part of the public interface of this service. */ - void registerGxsMailsClient( GxsMailsClient::GxsMailSubServices serviceType, + void registerGxsMailsClient( GxsMailSubServices serviceType, GxsMailsClient* service ); /// @see RsGenExchange::getServiceInfo() virtual RsServiceInfo getServiceInfo() { return RsServiceInfo( RS_SERVICE_TYPE_GXS_MAIL, "GXS Mails", 0, 1, 0, 1 ); } private: - /// @see GxsTokenQueue::handleResponse(uint32_t token, uint32_t req_type) - virtual void handleResponse(uint32_t token, uint32_t req_type); - - /// @see RsGenExchange::service_tick() - virtual void service_tick(); - - /// @see RsGenExchange::service_CreateGroup(...) - RsGenExchange::ServiceCreate_Return service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySet&); - - /// @see RsGenExchange::notifyChanges(std::vector &changes) - void notifyChanges(std::vector &changes); - /** Time interval of inactivity before a distribution group is unsubscribed. * Approximatively 3 months seems ok ATM. */ const static int32_t UNUSED_GROUP_UNSUBSCRIBE_INTERVAL = 0x76A700; @@ -134,7 +102,7 @@ private: * Tought it can't be too little as this may cause signed receipts to * get lost thus causing resend and fastly grow perceived async latency, in * case two sporadically connected users sends mails each other. - * TODO: While it is ok for signed acknowledged to stays in the DB for a + * While it is ok for signed acknowledged to stays in the DB for a * full GXS_STORAGE_PERIOD, mails should be removed as soon as a valid * signed acknowledged is received for each of them. * Two weeks seems fair ATM. @@ -159,37 +127,54 @@ private: p3IdService& idService; /// Stores pointers to client services to notify them about new mails - std::map servClients; + std::map servClients; RsMutex servClientsMutex; - struct OutgoingRecord - { - OutgoingRecord( RsGxsId rec, GxsMailsClient::GxsMailSubServices cs, - const uint8_t* data, uint32_t size ) : - status(GxsMailStatus::PENDING_PROCESSING), recipient(rec), - clientService(cs) - { - mailData.resize(size); - memcpy(&mailData[0], data, size); - } - - GxsMailStatus status; - RsGxsId recipient; - RsGxsMailItem mailItem; /// Don't use a pointer would be invalid after publish - std::vector mailData; - GxsMailsClient::GxsMailSubServices clientService; - RsNxsMailPresignedReceipt presignedReceipt; - }; - /// Keep track of mails while being processed + /** + * @brief Keep track of outgoing mails. + * Records enter the queue when a mail is sent, and are removed when a + * receipt has been received or sending is considered definetly failed. + * Items are saved in config for consistence accross RetroShare shutdowns. + */ typedef std::map prMap; prMap outgoingQueue; RsMutex outgoingMutex; void processOutgoingRecord(OutgoingRecord& r); + /** + * @brief Ingoing mail and receipt processing queue. + * Items are saved in config and then deleted in destructor for consistence + * accross RetroShare shutdowns. + */ typedef std::unordered_multimap inMap; inMap ingoingQueue; RsMutex ingoingMutex; + /// @see GxsTokenQueue::handleResponse(uint32_t token, uint32_t req_type) + virtual void handleResponse(uint32_t token, uint32_t req_type); + + /// @see RsGenExchange::service_tick() + virtual void service_tick(); + + /// @see RsGenExchange::service_CreateGroup(...) + RsGenExchange::ServiceCreate_Return service_CreateGroup( + RsGxsGrpItem* grpItem, RsTlvSecurityKeySet& ); + + /// @see RsGenExchange::notifyChanges(std::vector &changes) + void notifyChanges(std::vector &changes); + + /// @see p3Config::setupSerialiser() + virtual RsSerialiser* setupSerialiser(); + + /// @see p3Config::saveList(bool &cleanup, std::list&) + virtual bool saveList(bool &cleanup, std::list&saveList); + + /// @see p3Config::saveDone() + void saveDone(); + + /// @see p3Config::loadList(std::list&) + virtual bool loadList(std::list& loadList); + /// Request groups list to GXS backend. Async method. bool requestGroupsData(const std::list* groupIds = NULL); @@ -267,6 +252,7 @@ struct TestGxsMailClientService : GxsMailsClient, RsSingleJobThread /// @see RsSingleJobThread::run() virtual void run() { +#if 0 usleep(10*1000*1000); RsGxsId gxsidA("d0df7474bdde0464679e6ef787890287"); RsGxsId gxsidB("d060bea09dfa14883b5e6e517eb580cd"); @@ -274,23 +260,23 @@ struct TestGxsMailClientService : GxsMailsClient, RsSingleJobThread if(idService.isOwnId(gxsidA)) { std::string ciao("CiAone!"); - mailService.sendMail( mailId, GxsMailsClient::TEST_SERVICE, gxsidA, - gxsidB, + mailService.sendMail( mailId, GxsMailSubServices::TEST_SERVICE, + gxsidA, gxsidB, reinterpret_cast(ciao.data()), ciao.size() ); } else if(idService.isOwnId(gxsidB)) { std::string ciao("CiBuono!"); - mailService.sendMail( mailId, GxsMailsClient::TEST_SERVICE, gxsidB, - gxsidA, + mailService.sendMail( mailId, GxsMailSubServices::TEST_SERVICE, + gxsidB, gxsidA, reinterpret_cast(ciao.data()), ciao.size() ); } +#endif } private: p3GxsMails& mailService; p3IdService& idService; }; - diff --git a/libretroshare/src/services/p3msgservice.cc b/libretroshare/src/services/p3msgservice.cc index e4b302443..4bb0eabcf 100644 --- a/libretroshare/src/services/p3msgservice.cc +++ b/libretroshare/src/services/p3msgservice.cc @@ -105,7 +105,8 @@ p3MsgService::p3MsgService( p3ServiceControl *sc, p3IdService *id_serv, if(sc) initStandardTagTypes(); // Initialize standard tag types - gxsMailService.registerGxsMailsClient(GxsMailsClient::P3_MSG_SERVICE, this); + gxsMailService.registerGxsMailsClient( GxsMailSubServices::P3_MSG_SERVICE, + this ); } const std::string MSG_APP_NAME = "msg"; @@ -452,8 +453,14 @@ int p3MsgService::checkOutgoingMessages() return 0; } -bool p3MsgService::saveList(bool& cleanup, std::list& itemList) +bool p3MsgService::saveList(bool& cleanup, std::list& itemList) { + RsMsgGRouterMap* gxsmailmap = new RsMsgGRouterMap; + { + RS_STACK_MUTEX(gxsOngoingMutex); + gxsmailmap->ongoing_msgs = gxsOngoingMessages; + } + itemList.push_front(gxsmailmap); std::map::iterator mit; std::map::iterator mit2; @@ -461,9 +468,7 @@ bool p3MsgService::saveList(bool& cleanup, std::list& itemList) std::map::iterator lit; std::map::iterator mit4; - MsgTagType stdTags; - - cleanup = true; + cleanup = true; mMsgMtx.lock(); @@ -508,7 +513,7 @@ bool p3MsgService::saveList(bool& cleanup, std::list& itemList) kv.value = RsUtil::NumberToString(mDistantMessagePermissions) ; vitem->tlvkvs.pairs.push_back(kv) ; - itemList.push_back(vitem) ; + itemList.push_back(vitem); return true; } @@ -570,8 +575,19 @@ void p3MsgService::initStandardTagTypes() } } -bool p3MsgService::loadList(std::list& load) +bool p3MsgService::loadList(std::list& load) { + auto gxsmIt = load.begin(); + RsMsgGRouterMap* gxsmailmap = dynamic_cast(*gxsmIt); + if(gxsmailmap) + { + { + RS_STACK_MUTEX(gxsOngoingMutex); + gxsOngoingMessages = gxsmailmap->ongoing_msgs; + } + delete *gxsmIt; load.erase(gxsmIt); + } + RsMsgItem *mitem; RsMsgTagType* mtt; RsMsgTags* mti; @@ -581,7 +597,7 @@ bool p3MsgService::loadList(std::list& load) RsMsgDistantMessagesHashMap *ghm; std::list items; - std::list::iterator it; + std::list::iterator it; std::map::iterator tagIt; std::map srcIdMsgMap; std::map::iterator srcIt; @@ -589,10 +605,10 @@ bool p3MsgService::loadList(std::list& load) uint32_t max_msg_id = 0 ; // load items and calculate next unique msgId - for(it = load.begin(); it != load.end(); ++it) + for(it = load.begin(); it != load.end(); ++it) { - if (NULL != (mitem = dynamic_cast(*it))) + if (NULL != (mitem = dynamic_cast(*it))) { /* STORE MsgID */ if (mitem->msgId > max_msg_id) @@ -600,7 +616,7 @@ bool p3MsgService::loadList(std::list& load) items.push_back(mitem); } - else if (NULL != (grm = dynamic_cast(*it))) + else if (NULL != (grm = dynamic_cast(*it))) { // merge. for(std::map::const_iterator it(grm->ongoing_msgs.begin());it!=grm->ongoing_msgs.end();++it) @@ -620,7 +636,7 @@ bool p3MsgService::loadList(std::list& load) std::cerr << " " << it->first << " received " << time(NULL)-it->second << " secs ago." << std::endl; #endif } - else if(NULL != (mtt = dynamic_cast(*it))) + else if(NULL != (mtt = dynamic_cast(*it))) { // delete standard tags as they are now save in config if(mTags.end() == (tagIt = mTags.find(mtt->tagId))) @@ -635,23 +651,23 @@ bool p3MsgService::loadList(std::list& load) } } - else if(NULL != (mti = dynamic_cast(*it))) + else if(NULL != (mti = dynamic_cast(*it))) { mMsgTags.insert(std::pair(mti->msgId, mti)); } - else if(NULL != (msi = dynamic_cast(*it))) + else if(NULL != (msi = dynamic_cast(*it))) { srcIdMsgMap.insert(std::pair(msi->msgId, msi->srcId)); mSrcIds.insert(std::pair(msi->msgId, msi)); // does not need to be kept } - else if(NULL != (msp = dynamic_cast(*it))) + else if(NULL != (msp = dynamic_cast(*it))) { mParentId.insert(std::pair(msp->msgId, msp)); } RsConfigKeyValueSet *vitem = NULL ; - if(NULL != (vitem = dynamic_cast(*it))) + if(NULL != (vitem = dynamic_cast(*it))) { for(std::list::const_iterator kit = vitem->tlvkvs.pairs.begin(); kit != vitem->tlvkvs.pairs.end(); ++kit) { @@ -682,7 +698,7 @@ bool p3MsgService::loadList(std::list& load) } } - delete *it ; + delete *it ; continue ; } } @@ -700,7 +716,7 @@ bool p3MsgService::loadList(std::list& load) mitem->msgId = getNewUniqueMsgId(); } - RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/ + RS_STACK_MUTEX(mMsgMtx); srcIt = srcIdMsgMap.find(mitem->msgId); if(srcIt != srcIdMsgMap.end()) { @@ -1888,19 +1904,21 @@ void p3MsgService::notifyDataStatus( const GRouterMsgPropagationId& id, mDistantOutgoingMsgSigners[msg_id] = signer_id; std::map::iterator mit = msgOutgoing.find(msg_id); - if(mit == msgOutgoing.end()) { - std::cerr << " (EE) message has been notified as not delivered, " - << "but it not on outgoing list. Something's wrong!!" + std::cerr << " (II) message has been notified as not delivered, " + << "but it's not in outgoing list. Probably it has been " + << "delivered successfully by other means." << std::endl; - return; } - std::cerr << " reseting the ROUTED flag so that the message is " - << "requested again" << std::endl; + else + { + std::cerr << " reseting the ROUTED flag so that the message is " + << "requested again" << std::endl; - // clear the routed flag so that the message is requested again - mit->second->msgFlags &= ~RS_MSG_FLAGS_ROUTED; + // clear the routed flag so that the message is requested again + mit->second->msgFlags &= ~RS_MSG_FLAGS_ROUTED; + } return; } @@ -1918,15 +1936,15 @@ void p3MsgService::notifyDataStatus( const GRouterMsgPropagationId& id, return; } - uint32_t msg_id = it->second ; + uint32_t msg_id = it->second; // we should now remove the item from the msgOutgoing list. - std::map::iterator it2 = msgOutgoing.find(msg_id); if(it2 == msgOutgoing.end()) { - std::cerr << "(EE) message has been ACKed, but is not in outgoing " - << "list. Something's wrong!!" << std::endl; + std::cerr << "(II) message has been notified as delivered, but it's" + << " not in outgoing list. Probably it has been delivered" + << " successfully by other means." << std::endl; return; } @@ -1972,6 +1990,9 @@ uint32_t p3MsgService::getDistantMessagingPermissionFlags() bool p3MsgService::receiveGxsMail( const RsGxsMailItem& originalMessage, const uint8_t* data, uint32_t dataSize ) { + std::cout << "p3MsgService::receiveGxsMail(" << originalMessage.mailId + << ",, " << dataSize << ")" << std::endl; + Sha1CheckSum hash = RsDirUtil::sha1sum(data, dataSize); { @@ -1979,9 +2000,9 @@ bool p3MsgService::receiveGxsMail( const RsGxsMailItem& originalMessage, if( mRecentlyReceivedMessageHashes.find(hash) != mRecentlyReceivedMessageHashes.end() ) { - std::cerr << "p3MsgService::receiveGxsMail(...) (WW) receiving " - << "message of hash " << hash << " more than once. This " - << "is not a bug, unless it happens very often." + std::cerr << "p3MsgService::receiveGxsMail(...) (II) receiving " + << "message of hash " << hash << " more than once. " + << "Probably it has arrived before by other means." << std::endl; return true; } @@ -2016,6 +2037,58 @@ bool p3MsgService::receiveGxsMail( const RsGxsMailItem& originalMessage, bool p3MsgService::notifySendMailStatus( const RsGxsMailItem& originalMessage, GxsMailStatus status ) { + std::cout << "p3MsgService::notifySendMailStatus(" << originalMessage.mailId + << ", " << static_cast(status) << ")" << std::endl; + + if( status == GxsMailStatus::RECEIPT_RECEIVED ) + { + uint32_t msg_id; + + { + RS_STACK_MUTEX(gxsOngoingMutex); + + auto it = gxsOngoingMessages.find(originalMessage.mailId); + if(it == gxsOngoingMessages.end()) + { + std::cerr << "p3MsgService::notifySendMailStatus(" + << originalMessage.mailId + << ", " << static_cast(status) << ") " + << "(EE) cannot find pending message to acknowledge!" + << std::endl; + return false; + } + + msg_id = it->second; + } + + // we should now remove the item from the msgOutgoing list. + + { + RS_STACK_MUTEX(mMsgMtx); + + auto it2 = msgOutgoing.find(msg_id); + if(it2 == msgOutgoing.end()) + { + std::cerr << "p3MsgService::notifySendMailStatus(" + << originalMessage.mailId + << ", " << static_cast(status) << ") (II) " + << "received receipt for message that is not in " + << "outgoing list, probably it has been acknoweldged " + << "before by other means." << std::endl; + return true; + } + + delete it2->second; + msgOutgoing.erase(it2); + } + + RsServer::notify()->notifyListChange( NOTIFY_LIST_MESSAGELIST, + NOTIFY_TYPE_ADD ); + IndicateConfigChanged(); + + return true; + } + if( status >= GxsMailStatus::FAILED_RECEIPT_SIGNATURE ) { uint32_t msg_id; @@ -2025,7 +2098,7 @@ bool p3MsgService::notifySendMailStatus( const RsGxsMailItem& originalMessage, std::cerr << "p3MsgService::notifySendMailStatus(...) mail delivery" << "mailId: " << originalMessage.mailId - << " failed with " << static_cast(status); + << " failed with " << static_cast(status); auto it = gxsOngoingMessages.find(originalMessage.mailId); if(it == gxsOngoingMessages.end()) @@ -2058,49 +2131,6 @@ bool p3MsgService::notifySendMailStatus( const RsGxsMailItem& originalMessage, return true; } } - - if( status == GxsMailStatus::RECEIPT_RECEIVED ) - { - uint32_t msg_id; - - { - RS_STACK_MUTEX(gxsOngoingMutex); - - auto it = gxsOngoingMessages.find(originalMessage.mailId); - if(it == gxsOngoingMessages.end()) - { - std::cerr << " (EE) cannot find pending message to acknowledge. " - << "Weird.mailId = " << originalMessage.mailId - << std::endl; - return false; - } - - msg_id = it->second; - } - - // we should now remove the item from the msgOutgoing list. - - { - RS_STACK_MUTEX(mMsgMtx); - - auto it2 = msgOutgoing.find(msg_id); - if(it2 == msgOutgoing.end()) - { - std::cerr << "(EE) message has been ACKed, but is not in " - << "outgoing list. Something's wrong!!" << std::endl; - return true; - } - - delete it2->second; - msgOutgoing.erase(it2); - } - - RsServer::notify()->notifyListChange( NOTIFY_LIST_MESSAGELIST, - NOTIFY_TYPE_ADD ); - IndicateConfigChanged(); - - return true; - } } void p3MsgService::receiveGRouterData( const RsGxsId &destination_key, @@ -2122,9 +2152,9 @@ void p3MsgService::receiveGRouterData( const RsGxsId &destination_key, if( mRecentlyReceivedMessageHashes.find(hash) != mRecentlyReceivedMessageHashes.end() ) { - std::cerr << "p3MsgService::receiveGRouterData(...) (WW) receiving" + std::cerr << "p3MsgService::receiveGRouterData(...) (II) receiving" << "distant message of hash " << hash << " more than once" - << ". This is not a bug, unless it happens very often." + << ". Probably it has arrived before by other means." << std::endl; free(data); return; @@ -2218,9 +2248,9 @@ void p3MsgService::sendDistantMsgItem(RsMsgItem *msgitem) msg_serialized_data, msg_serialized_rssize, signing_key_id, grouter_message_id ); RsGxsMailId gxsMailId; - gxsMailService.sendMail( gxsMailId, P3_MSG_SERVICE, signing_key_id, - destination_key_id, msg_serialized_data, - msg_serialized_rssize ); + gxsMailService.sendMail( gxsMailId, GxsMailSubServices::P3_MSG_SERVICE, + signing_key_id, destination_key_id, + msg_serialized_data, msg_serialized_rssize ); /* now store the grouter id along with the message id, so that we can keep * track of received messages */ diff --git a/libretroshare/src/services/p3msgservice.h b/libretroshare/src/services/p3msgservice.h index a40dfd704..8bfd1b89a 100644 --- a/libretroshare/src/services/p3msgservice.h +++ b/libretroshare/src/services/p3msgservice.h @@ -150,6 +150,7 @@ private: * The map is indexed by the hash */ std::map _ongoing_messages; + /// Contains ongoing messages handed to gxs mail std::map gxsOngoingMessages; RsMutex gxsOngoingMutex; From e2078ba6cf4e76357149ed3f1008996e44843539 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Sun, 26 Feb 2017 11:30:04 +0100 Subject: [PATCH 19/35] Disable gxs mail test subservice by default --- libretroshare/src/rsserver/rsinit.cc | 5 ++++- libretroshare/src/services/p3gxsmails.h | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index 1ec7a4b54..ee2853502 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -1495,9 +1495,10 @@ int RsServer::StartupRetroShare() mGxsIdService, pgpAuxUtils); mGxsMails->setNetworkExchangeService(gxsmails_ns); pqih->addService(gxsmails_ns, true); - +# ifdef TEST_RS_GXS_MAIL TestGxsMailClientService* tgms = new TestGxsMailClientService(*mGxsMails, *mGxsIdService); +# endif // TEST_RS_GXS_MAIL # endif // RS_GXS_MAIL // remove pword from memory @@ -1831,7 +1832,9 @@ int RsServer::StartupRetroShare() # ifdef RS_GXS_MAIL startServiceThread(mGxsMails, "gxs mail"); startServiceThread(gxsmails_ns, "gxs mail ns"); +# ifdef TEST_RS_GXS_MAIL tgms->start("Gxs Mail Test Service"); +# endif // TEST_RS_GXS_MAIL # endif // RS_GXS_MAIL #endif // RS_ENABLE_GXS diff --git a/libretroshare/src/services/p3gxsmails.h b/libretroshare/src/services/p3gxsmails.h index a48ca58d7..6a717c1c5 100644 --- a/libretroshare/src/services/p3gxsmails.h +++ b/libretroshare/src/services/p3gxsmails.h @@ -216,6 +216,8 @@ private: void notifyClientService(const OutgoingRecord& pr); }; +#ifdef TEST_RS_GXS_MAIL + struct TestGxsMailClientService : GxsMailsClient, RsSingleJobThread { TestGxsMailClientService( p3GxsMails& gxsMailService, @@ -280,3 +282,6 @@ private: p3GxsMails& mailService; p3IdService& idService; }; + +#endif // TEST_RS_GXS_MAIL + From 3761b1473415d67309bb54d713eec31d329e2318 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Sun, 26 Feb 2017 12:13:00 +0100 Subject: [PATCH 20/35] Add some documentation to p3GxsMails --- libretroshare/src/services/p3gxsmails.h | 29 +++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/libretroshare/src/services/p3gxsmails.h b/libretroshare/src/services/p3gxsmails.h index 6a717c1c5..d1c74ea55 100644 --- a/libretroshare/src/services/p3gxsmails.h +++ b/libretroshare/src/services/p3gxsmails.h @@ -28,6 +28,8 @@ #include "util/rsthreads.h" struct p3GxsMails; + +/// Services who want to make use of p3GxsMails should inherit this struct struct GxsMailsClient { /** @@ -40,10 +42,37 @@ struct GxsMailsClient virtual bool receiveGxsMail( const RsGxsMailItem& originalMessage, const uint8_t* data, uint32_t dataSize ) = 0; + /** + * This will be called by p3GxsMails to notify the subservice about the + * status of a sent email. + * @param originalMessage message for with the notification is made + * @param status the new status of the message + * @return true if notification goes fine, false otherwise (ignored ATM) + */ virtual bool notifySendMailStatus( const RsGxsMailItem& originalMessage, GxsMailStatus status ) = 0; }; +/** + * @brief p3GxsMails is a mail delivery service based on GXS. + * p3GxsMails is capable of asynchronous mail delivery and acknowledgement. + * p3GxsMails is meant to be capable of multiple encryption options, + * @see RsGxsMailEncryptionMode at moment messages are encrypted using RSA + * unless the user ask for them being sent in clear text ( this is not supposed + * to happen in non testing environment so warnings and stack traces are printed + * in the log if an attempt to send something in clear text is made ). + * p3GxsMails try to hide metadata so the travelling message signed by the author + * but the recipient is not disclosed, instead to avoid everyone trying to + * decrypt every message a hint has been introduced, the hint is calculated in a + * way that one can easily prove that a message is not destined to someone, but + * cannot prove the message is destined to someone + * @see RsGxsMailItem::recipientsHint for more details. + * p3GxsMails expose a simple API to send and receive mails, the API also + * provide notification for the sending mail status @see sendMail(...), + * @see querySendMailStatus(...), @see registerGxsMailsClient(...), + * @see GxsMailsClient::receiveGxsMail(...), + * @see GxsMailsClient::notifySendMailStatus(...). + */ struct p3GxsMails : RsGenExchange, GxsTokenQueue, p3Config { p3GxsMails( RsGeneralDataService* gds, RsNetworkExchangeService* nes, From b4727bde29b57db2033fc0a9603f18c992cf3c4b Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Sun, 26 Feb 2017 13:06:38 +0100 Subject: [PATCH 21/35] Gxs Mail disabling is not supported ATM Fix some compiler warning Make travis-ci qmake parser happy with { --- libretroshare/src/libretroshare.pro | 3 +-- libretroshare/src/services/p3msgservice.cc | 16 ++++++++++++---- retroshare.pri | 10 +++++----- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index d94d7005b..dbbe6414b 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -852,8 +852,7 @@ gxsphotoshare { serialiser/rsphotoitems.cc \ } -rs_gxs_mail -{ +rs_gxs_mail { HEADERS += serialiser/rsgxsmailitems.h services/p3gxsmails.h SOURCES += serialiser/rsgxsmailitems.cc services/p3gxsmails.cpp } diff --git a/libretroshare/src/services/p3msgservice.cc b/libretroshare/src/services/p3msgservice.cc index 4bb0eabcf..de310db3b 100644 --- a/libretroshare/src/services/p3msgservice.cc +++ b/libretroshare/src/services/p3msgservice.cc @@ -85,10 +85,11 @@ static const uint32_t RS_MSG_DISTANT_MESSAGE_HASH_KEEP_TIME = 2*30*86400 ; // ke p3MsgService::p3MsgService( p3ServiceControl *sc, p3IdService *id_serv, p3GxsMails& gxsMS ) - : p3Service(), p3Config(), mIdService(id_serv), mServiceCtrl(sc), - mMsgMtx("p3MsgService"), mMsgUniqueId(0), gxsMailService(gxsMS), - gxsOngoingMutex("p3MsgService Gxs Outgoing Mutex"), - recentlyReceivedMutex("p3MsgService recently received hash mutex") + : p3Service(), p3Config(), + gxsOngoingMutex("p3MsgService Gxs Outgoing Mutex"), mIdService(id_serv), + mServiceCtrl(sc), mMsgMtx("p3MsgService"), mMsgUniqueId(0), + recentlyReceivedMutex("p3MsgService recently received hash mutex"), + gxsMailService(gxsMS) { /* this serialiser is used for services. It's not the same than the one * returned by setupSerialiser(). We need both!! */ @@ -2030,8 +2031,13 @@ bool p3MsgService::receiveGxsMail( const RsGxsMailItem& originalMessage, handleIncomingItem(msg_item); } else + { std::cerr << "p3MsgService::receiveGxsMail(...) Item could not be " << "deserialised. Format error??" << std::endl; + return false; + } + + return true; } bool p3MsgService::notifySendMailStatus( const RsGxsMailItem& originalMessage, @@ -2131,6 +2137,8 @@ bool p3MsgService::notifySendMailStatus( const RsGxsMailItem& originalMessage, return true; } } + + return true; } void p3MsgService::receiveGRouterData( const RsGxsId &destination_key, diff --git a/retroshare.pri b/retroshare.pri index a794cb29d..52d81d9a1 100644 --- a/retroshare.pri +++ b/retroshare.pri @@ -60,10 +60,10 @@ rs_nodeprecatedwarning:CONFIG -= no_rs_nodeprecatedwarning CONFIG *= no_rs_nocppwarning rs_nocppwarning:CONFIG -= no_rs_nocppwarning -# To enable GXS mail append the following assignation to qmake command line -# "CONFIG+=rs_gxs_mail" -CONFIG *= no_rs_gxs_mail -rs_gxs_mail:CONFIG -= no_rs_gxs_mail +# To disable GXS mail append the following assignation to qmake command line +# "CONFIG+=no_rs_gxs_mail" +CONFIG *= rs_gxs_mail +#no_rs_gxs_mail:CONFIG -= rs_gxs_mail ## Disabing not supported ATM unix { @@ -179,7 +179,7 @@ rs_nodeprecatedwarning { rs_nocppwarning { QMAKE_CXXFLAGS += -Wno-cpp DEFINES *= RS_NO_WARN_CPP - warning("QMAKE: You have disable cpp warnings.") + warning("QMAKE: You have disable C preprocessor warnings.") } rs_gxs_mail:DEFINES *= RS_GXS_MAIL From 7c74cae1ef0f77384f41140a4a050aaa338c9409 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Sun, 26 Feb 2017 13:13:55 +0100 Subject: [PATCH 22/35] Force C++11 if gxs mail is enabled --- retroshare.pri | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/retroshare.pri b/retroshare.pri index 52d81d9a1..05ccf0469 100644 --- a/retroshare.pri +++ b/retroshare.pri @@ -182,4 +182,12 @@ rs_nocppwarning { warning("QMAKE: You have disable C preprocessor warnings.") } -rs_gxs_mail:DEFINES *= RS_GXS_MAIL +rs_gxs_mail { + DEFINES *= RS_GXS_MAIL + greaterThan(QT_MAJOR_VERSION, 4) { + CONFIG += c++11 + } else { + QMAKE_CXXFLAGS += -std=c++0x + } +} + From 2b1c9b74d1dd55d7b44f3b0c90ba39767a3da7d1 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Mon, 27 Feb 2017 09:06:35 +0100 Subject: [PATCH 23/35] Fix compilation on systems without uint like windows --- libretroshare/src/services/p3gxsmails.cpp | 1 + libretroshare/src/services/p3msgservice.cc | 2 ++ 2 files changed, 3 insertions(+) diff --git a/libretroshare/src/services/p3gxsmails.cpp b/libretroshare/src/services/p3gxsmails.cpp index 55667cf9a..a4957b4e7 100644 --- a/libretroshare/src/services/p3gxsmails.cpp +++ b/libretroshare/src/services/p3gxsmails.cpp @@ -19,6 +19,7 @@ #include "p3gxsmails.h" #include "util/stacktrace.h" +typedef unsigned int uint; p3GxsMails::~p3GxsMails() { diff --git a/libretroshare/src/services/p3msgservice.cc b/libretroshare/src/services/p3msgservice.cc index de310db3b..6da7a91b7 100644 --- a/libretroshare/src/services/p3msgservice.cc +++ b/libretroshare/src/services/p3msgservice.cc @@ -65,6 +65,8 @@ //#define DISABLE_DISTANT_MESSAGES //#define DEBUG_DISTANT_MSG +typedef unsigned int uint; + using namespace Rs::Msgs; static struct RsLog::logInfo msgservicezoneInfo = {RsLog::Default, "msgservice"}; From f19fe56a93d11c3788f24ea42a7bf460f7a86db6 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Mon, 27 Feb 2017 10:31:26 +0100 Subject: [PATCH 24/35] Better documentation about multimap usage --- libretroshare/src/services/p3gxsmails.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libretroshare/src/services/p3gxsmails.h b/libretroshare/src/services/p3gxsmails.h index d1c74ea55..7941f8aa3 100644 --- a/libretroshare/src/services/p3gxsmails.h +++ b/libretroshare/src/services/p3gxsmails.h @@ -172,8 +172,12 @@ private: /** * @brief Ingoing mail and receipt processing queue. - * Items are saved in config and then deleted in destructor for consistence - * accross RetroShare shutdowns. + * At shutdown remaining items are saved in config and then deleted in + * destructor for consistence accross RetroShare instances. + * In order to avoid malicious messages ( non malicious collision has 1/2^64 + * probablity ) to smash items in the queue thus causing previous incoming + * item to not being processed and memleaked multimap is used instead of map + * for incoming queue. */ typedef std::unordered_multimap inMap; inMap ingoingQueue; From 4c89641d3eb37f179d7fe671797fe2c7e6e63ed4 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Mon, 27 Feb 2017 22:18:37 +0100 Subject: [PATCH 25/35] p3ChatService support async distant chat via Gxs To implement async distant chat p3ChatService use p3GxsMails in a similar way that has been done with p3MsgService tought as p3ChatService was not thinked for async comunication in the first place the result is quite clumsy. A proper chat service should be rewritten from scratch in the near future, with proper chat history and other desiderables features. deprecated empty p3ChatService::locked_storeIncomingMsg(...) --- libretroshare/src/chat/p3chatservice.cc | 446 +++++++++++------- libretroshare/src/chat/p3chatservice.h | 47 +- libretroshare/src/chat/rschatitems.h | 161 ++++++- libretroshare/src/rsserver/rsinit.cc | 3 +- libretroshare/src/serialiser/rsgxsmailitems.h | 7 +- 5 files changed, 466 insertions(+), 198 deletions(-) diff --git a/libretroshare/src/chat/p3chatservice.cc b/libretroshare/src/chat/p3chatservice.cc index eb421ac31..d85ecc7e2 100644 --- a/libretroshare/src/chat/p3chatservice.cc +++ b/libretroshare/src/chat/p3chatservice.cc @@ -53,40 +53,30 @@ static const uint32_t MAX_AVATAR_JPEG_SIZE = 32767; // Maximum size // don't transfer correctly and can kill the system. // Images are 96x96, which makes approx. 27000 bytes uncompressed. -p3ChatService::p3ChatService(p3ServiceControl *sc,p3IdService *pids, p3LinkMgr *lm, p3HistoryMgr *historyMgr) - : DistributedChatService(getServiceInfo().mServiceType,sc,historyMgr,pids), mChatMtx("p3ChatService"),mServiceCtrl(sc), mLinkMgr(lm) , mHistoryMgr(historyMgr) +p3ChatService::p3ChatService( p3ServiceControl *sc, p3IdService *pids, + p3LinkMgr *lm, p3HistoryMgr *historyMgr, + p3GxsMails& gxsMailService ) : + DistributedChatService(getServiceInfo().mServiceType, sc, historyMgr,pids), + mChatMtx("p3ChatService"), mServiceCtrl(sc), mLinkMgr(lm), + mHistoryMgr(historyMgr), _own_avatar(NULL), + _serializer(new RsChatSerialiser()), mGxsTransport(gxsMailService), + recentlyReceivedMutex("p3ChatService recently received mutex") { - _serializer = new RsChatSerialiser() ; - - _own_avatar = NULL ; - _custom_status_string = "" ; - - addSerialType(_serializer) ; + addSerialType(_serializer); + mGxsTransport.registerGxsMailsClient( GxsMailSubServices::P3_CHAT_SERVICE, + this ); } -const std::string CHAT_APP_NAME = "chat"; -const uint16_t CHAT_APP_MAJOR_VERSION = 1; -const uint16_t CHAT_APP_MINOR_VERSION = 0; -const uint16_t CHAT_MIN_MAJOR_VERSION = 1; -const uint16_t CHAT_MIN_MINOR_VERSION = 0; - RsServiceInfo p3ChatService::getServiceInfo() -{ - return RsServiceInfo(RS_SERVICE_TYPE_CHAT, - CHAT_APP_NAME, - CHAT_APP_MAJOR_VERSION, - CHAT_APP_MINOR_VERSION, - CHAT_MIN_MAJOR_VERSION, - CHAT_MIN_MINOR_VERSION); -} +{ return RsServiceInfo(RS_SERVICE_TYPE_CHAT, "chat", 1, 0, 1, 0); } int p3ChatService::tick() { - if(receivedItems()) - receiveChatQueue(); + if(receivedItems()) receiveChatQueue(); - DistributedChatService::flush() ; - //DistantChatService::flush() ; + DistributedChatService::flush(); + + cleanListOfReceivedMessageHashes(); return 0; } @@ -253,12 +243,12 @@ void p3ChatService::clearChatLobby(const ChatId& id) void p3ChatService::sendChatItem(RsChatItem *item) { - if(DistantChatService::handleOutgoingItem(item)) - return ; + if(DistantChatService::handleOutgoingItem(item)) return; #ifdef CHAT_DEBUG - std::cerr << "p3ChatService::sendChatItem(): sending to " << item->PeerId() << ": interpreted as friend peer id." << std::endl; + std::cerr << "p3ChatService::sendChatItem(): sending to " << item->PeerId() + << ": interpreted as friend peer id." << std::endl; #endif - sendItem(item) ; + sendItem(item); } void p3ChatService::checkSizeAndSendMessage(RsChatMsgItem *msg) @@ -336,28 +326,49 @@ bool p3ChatService::sendChat(ChatId destination, std::string msg) message.incoming = false; message.online = true; - if(!isOnline(vpid)) + if(!isOnline(vpid)) { - /* peer is offline, add to outgoing list */ + message.online = false; + RsServer::notify()->notifyChatMessage(message); + + // use the history to load pending messages to the gui + // this is not very nice, because the user may think the message was send, while it is still in the queue + mHistoryMgr->addMessage(message); + + RsGxsMailId tId = RSRandom::random_u64(); + + if(destination.isDistantChatId()) { - RS_STACK_MUTEX(mChatMtx); - privateOutgoingList.push_back(ci); + DEPMap::const_iterator it = + mDistantGxsMap.find(destination.toDistantChatId()); + if(it != mDistantGxsMap.end()) + { + const DistantEndpoints& de(it->second); + uint32_t sz = ci->serial_size(); + std::vector data; data.resize(sz); + ci->serialise(&data[0], sz); + mGxsTransport.sendMail(tId, GxsMailSubServices::P3_CHAT_SERVICE, + de.from, de.to, &data[0], sz); + } + else + std::cout << "p3ChatService::sendChat(...) can't find distant" + << "chat id in mDistantGxsMap this is unxpected!" + << std::endl; } - message.online = false; - RsServer::notify()->notifyChatMessage(message); + // peer is offline, add to outgoing list + { + RS_STACK_MUTEX(mChatMtx); + privateOutgoingMap.insert(outMP::value_type(tId, ci)); + } - // use the history to load pending messages to the gui - // this is not very nice, because the user may think the message was send, while it is still in the queue - mHistoryMgr->addMessage(message); + IndicateConfigChanged(); + return false; + } - IndicateConfigChanged(); - return false; - } - - { - RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ - std::map::iterator it = _avatars.find(vpid) ; + { + RS_STACK_MUTEX(mChatMtx); + std::map::iterator it = _avatars.find(vpid); if(it == _avatars.end()) { @@ -505,50 +516,50 @@ class MsgCounter void p3ChatService::handleIncomingItem(RsItem *item) { #ifdef CHAT_DEBUG - std::cerr << "p3ChatService::receiveChatQueue() Item:" << (void*)item << std::endl ; + std::cerr << "p3ChatService::receiveChatQueue() Item:" << (void*)item + << std::endl ; #endif // RsChatMsgItems needs dynamic_cast, since they have derived siblings. - // - RsChatMsgItem *ci = dynamic_cast(item) ; - if(ci != NULL) + RsChatMsgItem* ci = dynamic_cast(item); + if(ci) { handleRecvChatMsgItem(ci); - - if(ci) - delete ci ; - return ; // don't delete! It's handled by handleRecvChatMsgItem in some specific cases only. + /* +ci+ deletion is handled by handleRecvChatMsgItem ONLY in some + * specific cases, in case +ci+ has not been handled deleted it here */ + delete ci ; + + return; } -// if(DistantChatService::handleRecvItem(dynamic_cast(item))) -// { -// delete item ; -// return ; -// } - - if(DistributedChatService::handleRecvItem(dynamic_cast(item))) + if(DistributedChatService::handleRecvItem(dynamic_cast(item))) { - delete item ; - return ; + delete item; + return; } switch(item->PacketSubType()) { - case RS_PKT_SUBTYPE_CHAT_STATUS: handleRecvChatStatusItem(dynamic_cast(item)) ; break ; - case RS_PKT_SUBTYPE_CHAT_AVATAR: handleRecvChatAvatarItem(dynamic_cast(item)) ; break ; - default: - { - static int already = false ; - - if(!already) - { - std::cerr << "Unhandled item subtype " << (int)item->PacketSubType() << " in p3ChatService: " << std::endl; - already = true ; - } - } + case RS_PKT_SUBTYPE_CHAT_STATUS: + handleRecvChatStatusItem(dynamic_cast(item)); + break; + case RS_PKT_SUBTYPE_CHAT_AVATAR: + handleRecvChatAvatarItem(dynamic_cast(item)); + break; + default: + { + static int already = false; + if(!already) + { + std::cerr << "Unhandled item subtype " + << static_cast(item->PacketSubType()) + << " in p3ChatService: " << std::endl; + already = true; + } } - delete item ; + } + delete item; } void p3ChatService::handleRecvChatAvatarItem(RsChatAvatarItem *ca) @@ -676,35 +687,105 @@ bool p3ChatService::checkForMessageSecurity(RsChatMsgItem *ci) return true ; } +bool p3ChatService::initiateDistantChatConnexion( + const RsGxsId& to_gxs_id, const RsGxsId& from_gxs_id, + DistantChatPeerId& pid, uint32_t& error_code ) +{ + if(DistantChatService::initiateDistantChatConnexion( to_gxs_id, + from_gxs_id, pid, + error_code )) + { + DistantEndpoints ep; ep.from = from_gxs_id; ep.to = to_gxs_id; + mDistantGxsMap.insert(DEPMap::value_type(pid, ep)); + return true; + } + return false; +} + +bool p3ChatService::receiveGxsMail(const RsGxsMailItem&, const uint8_t* data, uint32_t dataSize) +{ + RsChatMsgItem* item = new RsChatMsgItem( const_cast(data), + dataSize ); + handleRecvChatMsgItem(item); + delete item; + return true; +} + +bool p3ChatService::notifySendMailStatus(const RsGxsMailItem& originalMessage, GxsMailStatus status) +{ + if ( status != GxsMailStatus::RECEIPT_RECEIVED ) return true; + + bool changed = false; + + { + RS_STACK_MUTEX(mChatMtx); + auto it = privateOutgoingMap.find(originalMessage.mailId); + if( it != privateOutgoingMap.end() ) + { + privateOutgoingMap.erase(it); + changed = true; + } + } + + if(changed) + { + RsServer::notify()->notifyListChange( + NOTIFY_LIST_PRIVATE_OUTGOING_CHAT, NOTIFY_TYPE_DEL ); + + IndicateConfigChanged(); + } + + return true; +} + bool p3ChatService::handleRecvChatMsgItem(RsChatMsgItem *& ci) { time_t now = time(NULL); + + { // Check for duplicates + uint32_t sz = ci->serial_size(); + std::vector srz; srz.resize(sz); + ci->serialise(&srz[0], sz); + Sha1CheckSum hash = RsDirUtil::sha1sum(&srz[0], sz); + { + RS_STACK_MUTEX(recentlyReceivedMutex); + if( mRecentlyReceivedMessageHashes.find(hash) != + mRecentlyReceivedMessageHashes.end() ) + { + std::cerr << "p3ChatService::handleRecvChatMsgItem(...) (II) " + << "receiving distant message of hash " << hash + << " more than once. Probably it has arrived before " + << "by other means." << std::endl; + delete ci; ci=NULL; + return true; + } + mRecentlyReceivedMessageHashes[hash] = now; + } + } + std::string name; - uint32_t popupChatFlag = RS_POPUP_CHAT; + uint32_t popupChatFlag = RS_POPUP_CHAT; - { - RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + { + RS_STACK_MUTEX(mChatMtx); - if(!locked_checkAndRebuildPartialMessage(ci)) // we make sure this call does not take control over the memory - return true ; // message is a subpart of an existing message. So everything ok, but we need to return. - } + // we make sure this call does not take control over the memory + if(!locked_checkAndRebuildPartialMessage(ci)) return true; + /* message is a subpart of an existing message. + * So everything ok, but we need to return. */ + } - // Check for security. This avoids bombing messages, and so on. + // Check for security. This avoids bombing messages, and so on. + if(!checkForMessageSecurity(ci)) return false; - if(!checkForMessageSecurity(ci)) - return false ; - - // If it's a lobby item, we need to bounce it and possibly check for timings etc. - - if(!DistributedChatService::handleRecvChatLobbyMsgItem(ci)) - return false ; + /* If it's a lobby item, we need to bounce it and possibly check for timings + * etc. */ + if(!DistributedChatService::handleRecvChatLobbyMsgItem(ci)) return false; #ifdef CHAT_DEBUG - std::cerr << "p3ChatService::receiveChatQueue() Item:"; - std::cerr << std::endl; + std::cerr << "p3ChatService::receiveChatQueue() Item:" << std::endl; ci->print(std::cerr); - std::cerr << std::endl; - std::cerr << "Got msg. Flags = " << ci->chatFlags << std::endl ; + std::cerr << std::endl << "Got msg. Flags = " << ci->chatFlags << std::endl; #endif // Now treat normal chat stuff such as avatar requests, except for chat lobbies. @@ -1087,6 +1168,25 @@ RsChatStatusItem *p3ChatService::makeOwnCustomStateStringItem() return ci ; } + +void p3ChatService::cleanListOfReceivedMessageHashes() +{ + RS_STACK_MUTEX(recentlyReceivedMutex); + + time_t now = time(NULL); + + for( auto it = mRecentlyReceivedMessageHashes.begin(); + it != mRecentlyReceivedMessageHashes.end(); ) + if( now > RECENTLY_RECEIVED_INTERVAL + it->second ) + { + std::cerr << "p3MsgService(): cleanListOfReceivedMessageHashes(" + << "). Removing old hash " << it->first << ", aged " + << now - it->second << " secs ago." << std::endl; + + it = mRecentlyReceivedMessageHashes.erase(it); + } + else ++it; +} RsChatAvatarItem *p3ChatService::makeOwnAvatarItem() { RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ @@ -1100,11 +1200,11 @@ RsChatAvatarItem *p3ChatService::makeOwnAvatarItem() void p3ChatService::sendAvatarJpegData(const RsPeerId& peer_id) { - #ifdef CHAT_DEBUG - std::cerr << "p3chatservice: sending requested for peer " << peer_id << ", data=" << (void*)_own_avatar << std::endl ; - #endif +#ifdef CHAT_DEBUG + std::cerr << "p3chatservice: sending requested for peer " << peer_id << ", data=" << (void*)_own_avatar << std::endl ; +#endif - if(_own_avatar != NULL) + if(_own_avatar != NULL) { RsChatAvatarItem *ci = makeOwnAvatarItem(); ci->PeerId(peer_id); @@ -1144,19 +1244,34 @@ bool p3ChatService::loadList(std::list& load) for(std::list::const_iterator it(load.begin());it!=load.end();++it) { + if(PrivateOugoingMapItem* om=dynamic_cast(*it)) + { + RS_STACK_MUTEX(mChatMtx); + for( auto& pair : om->store ) + { + privateOutgoingMap.insert( + outMP::value_type(pair.first, + new RsChatMsgItem(pair.second)) ); + } + + delete om; continue; + } + + RsChatAvatarItem *ai = NULL ; if(NULL != (ai = dynamic_cast(*it))) { - RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + RS_STACK_MUTEX(mChatMtx); if(ai->image_size <= MAX_AVATAR_JPEG_SIZE) _own_avatar = new AvatarInfo(ai->image_data,ai->image_size) ; else - std::cerr << "Dropping avatar image, because its size is " << ai->image_size << ", and the maximum allowed size is " << MAX_AVATAR_JPEG_SIZE << std::endl; + std::cerr << "Dropping avatar image, because its size is " + << ai->image_size << ", and the maximum allowed size " + << "is " << MAX_AVATAR_JPEG_SIZE << std::endl; delete *it; - continue; } @@ -1164,40 +1279,42 @@ bool p3ChatService::loadList(std::list& load) if(NULL != (mitem = dynamic_cast(*it))) { - RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + RS_STACK_MUTEX(mChatMtx); _custom_status_string = mitem->status_string ; delete *it; - continue; } - RsPrivateChatMsgConfigItem *citem = NULL ; - - if(NULL != (citem = dynamic_cast(*it))) + /* TODO: G10h4ck 2017/02/27 this block is kept for retrocompatibility, + * and will be used just first time, to load messages in the old format + * should be removed in the following RS version */ + if( RsPrivateChatMsgConfigItem *citem = + dynamic_cast(*it) ) { - RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + RS_STACK_MUTEX(mChatMtx); - if (citem->chatFlags & RS_CHAT_FLAG_PRIVATE) { - if (std::find(ssl_peers.begin(), ssl_peers.end(), citem->configPeerId) != ssl_peers.end()) { + if ( citem->chatFlags & RS_CHAT_FLAG_PRIVATE ) + { + if ( std::find(ssl_peers.begin(), ssl_peers.end(), + citem->configPeerId) != ssl_peers.end() ) + { RsChatMsgItem *ci = new RsChatMsgItem(); citem->get(ci); - if (citem->configFlags & RS_CHATMSG_CONFIGFLAG_INCOMING) { + if (citem->configFlags & RS_CHATMSG_CONFIGFLAG_INCOMING) + { locked_storeIncomingMsg(ci); - } else { - privateOutgoingList.push_back(ci); } - } else { - // no friends + else privateOutgoingMap.insert( + outMP::value_type(RSRandom::random_u64(), ci) ); } - } else { - // ignore all other items + else { /* no friends */ } } + else { /* ignore all other items */ } delete *it; - continue; } @@ -1228,21 +1345,18 @@ bool p3ChatService::saveList(bool& cleanup, std::list& list) mChatMtx.lock(); /****** MUTEX LOCKED *******/ + PrivateOugoingMapItem* om = new PrivateOugoingMapItem; + typedef std::map::value_type vT; + for( auto& pair : privateOutgoingMap ) + om->store.insert(vT(pair.first, *pair.second)); + list.push_back(om); + + RsChatStatusItem *di = new RsChatStatusItem ; di->status_string = _custom_status_string ; di->flags = RS_CHAT_FLAG_CUSTOM_STATE ; - list.push_back(di) ; - - /* save outgoing private chat messages */ - std::list::iterator it; - for (it = privateOutgoingList.begin(); it != privateOutgoingList.end(); it++) { - RsPrivateChatMsgConfigItem *ci = new RsPrivateChatMsgConfigItem; - - ci->set(*it, (*it)->PeerId(), 0); - - list.push_back(ci); - } + list.push_back(di); DistributedChatService::addToSaveList(list) ; DistantChatService::addToSaveList(list) ; @@ -1269,54 +1383,51 @@ RsSerialiser *p3ChatService::setupSerialiser() void p3ChatService::statusChange(const std::list &plist) { - std::list::const_iterator it; - for (it = plist.begin(); it != plist.end(); ++it) { + for (auto it = plist.cbegin(); it != plist.cend(); ++it) + { if (it->actions & RS_SERVICE_PEER_CONNECTED) { /* send the saved outgoing messages */ bool changed = false; - std::vector to_send ; + std::vector to_send; - if (privateOutgoingList.size()) { - RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + RS_STACK_MUTEX(mChatMtx); - RsPeerId ownId = mServiceCtrl->getOwnId(); - - std::list::iterator cit = privateOutgoingList.begin(); - while (cit != privateOutgoingList.end()) { - RsChatMsgItem *c = *cit; - - if (c->PeerId() == it->id) { - //mHistoryMgr->addMessage(false, c->PeerId(), ownId, c); + for( auto cit = privateOutgoingMap.begin(); + cit != privateOutgoingMap.end(); ) + { + RsChatMsgItem *c = cit->second; + if (c->PeerId() == it->id) + { + //mHistoryMgr->addMessage(false, c->PeerId(), ownId, c); to_send.push_back(c) ; - changed = true; - - cit = privateOutgoingList.erase(cit); - + cit = privateOutgoingMap.erase(cit); continue; } ++cit; } - } /* UNLOCKED */ + } - for(uint32_t i=0;inotifyChatMessage(message); + for(auto toIt = to_send.begin(); toIt != to_send.end(); ++toIt) + { + ChatMessage message; + initChatMessage(*toIt, message); + message.incoming = false; + message.online = true; + RsServer::notify()->notifyChatMessage(message); - checkSizeAndSendMessage(to_send[i]); // delete item - } + checkSizeAndSendMessage(*toIt); // delete item + } - if (changed) { - RsServer::notify()->notifyListChange(NOTIFY_LIST_PRIVATE_OUTGOING_CHAT, NOTIFY_TYPE_DEL); + if (changed) + { + RsServer::notify()->notifyListChange( + NOTIFY_LIST_PRIVATE_OUTGOING_CHAT, NOTIFY_TYPE_DEL); IndicateConfigChanged(); } @@ -1324,18 +1435,17 @@ void p3ChatService::statusChange(const std::list &plist) else if (it->actions & RS_SERVICE_PEER_REMOVED) { /* now handle remove */ - mHistoryMgr->clear(ChatId(it->id)); + mHistoryMgr->clear(ChatId(it->id)); - std::list::iterator cit = privateOutgoingList.begin(); - while (cit != privateOutgoingList.end()) { - RsChatMsgItem *c = *cit; - if (c->PeerId() == it->id) { - cit = privateOutgoingList.erase(cit); - continue; - } - ++cit; - } - IndicateConfigChanged(); + RS_STACK_MUTEX(mChatMtx); + for ( auto cit = privateOutgoingMap.begin(); + cit != privateOutgoingMap.end(); ) + { + RsChatMsgItem *c = cit->second; + if (c->PeerId() == it->id) cit = privateOutgoingMap.erase(cit); + else ++cit; + } + IndicateConfigChanged(); } } } diff --git a/libretroshare/src/chat/p3chatservice.h b/libretroshare/src/chat/p3chatservice.h index 3096309b0..365ddb4a9 100644 --- a/libretroshare/src/chat/p3chatservice.h +++ b/libretroshare/src/chat/p3chatservice.h @@ -37,6 +37,8 @@ #include "chat/distantchat.h" #include "chat/distributedchat.h" #include "retroshare/rsmsgs.h" +#include "services/p3gxsmails.h" +#include "util/rsdeprecate.h" class p3ServiceControl; class p3LinkMgr; @@ -51,10 +53,12 @@ typedef RsPeerId ChatLobbyVirtualPeerId ; * This service uses rsnotify (callbacks librs clients (e.g. rs-gui)) * @see NotifyBase */ -class p3ChatService: public p3Service, public DistantChatService, public DistributedChatService, public p3Config, public pqiServiceMonitor +struct p3ChatService : + p3Service, DistantChatService, DistributedChatService, p3Config, + pqiServiceMonitor, GxsMailsClient { -public: - p3ChatService(p3ServiceControl *cs, p3IdService *pids,p3LinkMgr *cm, p3HistoryMgr *historyMgr); + p3ChatService( p3ServiceControl *cs, p3IdService *pids,p3LinkMgr *cm, + p3HistoryMgr *historyMgr, p3GxsMails& gxsMailService ); virtual RsServiceInfo getServiceInfo(); @@ -66,7 +70,7 @@ public: * : notifyCustomState, notifyChatStatus, notifyPeerHasNewAvatar * @see NotifyBase */ - virtual int tick(); + virtual int tick(); /*************** pqiMonitor callback ***********************/ virtual void statusChange(const std::list &plist); @@ -161,6 +165,20 @@ public: */ bool clearPrivateChatQueue(bool incoming, const RsPeerId &id); + virtual bool initiateDistantChatConnexion( const RsGxsId& to_gxs_id, + const RsGxsId& from_gxs_id, + DistantChatPeerId &pid, + uint32_t& error_code ); + + /// @see GxsMailsClient::receiveGxsMail(...) + virtual bool receiveGxsMail( const RsGxsMailItem& /*originalMessage*/, + const uint8_t* data, uint32_t dataSize ); + + /// @see GxsMailsClient::notifySendMailStatus(...) + virtual bool notifySendMailStatus( const RsGxsMailItem& originalMessage, + GxsMailStatus status ); + + protected: /************* from p3Config *******************/ virtual RsSerialiser *setupSerialiser() ; @@ -177,8 +195,9 @@ protected: /// This is to be used by subclasses/parents to call IndicateConfigChanged() virtual void triggerConfigSave() { IndicateConfigChanged() ; } + /// Same, for storing messages in incoming list - virtual void locked_storeIncomingMsg(RsChatMsgItem *) ; + RS_DEPRECATED virtual void locked_storeIncomingMsg(RsChatMsgItem *) ; private: RsMutex mChatMtx; @@ -231,7 +250,9 @@ private: p3LinkMgr *mLinkMgr; p3HistoryMgr *mHistoryMgr; - std::list privateOutgoingList; // messages waiting to be send when peer comes online + /// messages waiting to be send when peer comes online + typedef std::map outMP; + outMP privateOutgoingMap; AvatarInfo *_own_avatar ; std::map _avatars ; @@ -240,7 +261,19 @@ private: std::string _custom_status_string ; std::map _state_strings ; - RsChatSerialiser *_serializer ; + RsChatSerialiser *_serializer; + + struct DistantEndpoints { RsGxsId from; RsGxsId to; }; + typedef std::map DEPMap; + DEPMap mDistantGxsMap; + p3GxsMails& mGxsTransport; + + /** As we have multiple backends duplicates are possible, keep track of + * recently received messages hashes for at least 2h to avoid them */ + const static uint32_t RECENTLY_RECEIVED_INTERVAL = 2*3600; + std::map mRecentlyReceivedMessageHashes; + RsMutex recentlyReceivedMutex; + void cleanListOfReceivedMessageHashes(); }; class p3ChatService::StateStringInfo diff --git a/libretroshare/src/chat/rschatitems.h b/libretroshare/src/chat/rschatitems.h index 13b42c18f..b047f221f 100644 --- a/libretroshare/src/chat/rschatitems.h +++ b/libretroshare/src/chat/rschatitems.h @@ -75,6 +75,7 @@ const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_SIGNED_MSG = 0x17 ; const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_SIGNED_EVENT = 0x18 ; const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_LIST = 0x19 ; const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_INVITE = 0x1A ; +const uint8_t RS_PKT_SUBTYPE_OUTGOING_MAP = 0x1B ; typedef uint64_t ChatLobbyId ; typedef uint64_t ChatLobbyMsgId ; @@ -286,30 +287,32 @@ class RsChatLobbyInviteItem: public RsChatItem * For saving incoming and outgoing chat msgs * @see p3ChatService */ -class RsPrivateChatMsgConfigItem: public RsChatItem +struct RsPrivateChatMsgConfigItem : RsChatItem { - public: - RsPrivateChatMsgConfigItem() :RsChatItem(RS_PKT_SUBTYPE_PRIVATECHATMSG_CONFIG) {} - RsPrivateChatMsgConfigItem(void *data,uint32_t size) ; // deserialization + RsPrivateChatMsgConfigItem() :RsChatItem(RS_PKT_SUBTYPE_PRIVATECHATMSG_CONFIG) {} + RsPrivateChatMsgConfigItem(void *data,uint32_t size) ; // deserialization - virtual ~RsPrivateChatMsgConfigItem() {} - virtual void clear() {} - virtual std::ostream& print(std::ostream &out, uint16_t indent = 0); + virtual ~RsPrivateChatMsgConfigItem() {} + virtual void clear() {} + virtual std::ostream& print(std::ostream &out, uint16_t indent = 0); - virtual bool serialise(void *data,uint32_t& size) ; // Isn't it better that items can serialize themselves ? - virtual uint32_t serial_size() ; // deserialise is handled using a constructor + virtual bool serialise(void *data,uint32_t& size); + virtual uint32_t serial_size(); + /* Deserialize is handled using a constructor,it would be better have a + * deserialize method as constructor cannot fails while deserialization can. + */ - /* set data from RsChatMsgItem to RsPrivateChatMsgConfigItem */ - void set(RsChatMsgItem *ci, const RsPeerId &peerId, uint32_t confFlags); - /* get data from RsPrivateChatMsgConfigItem to RsChatMsgItem */ - void get(RsChatMsgItem *ci); + /* set data from RsChatMsgItem to RsPrivateChatMsgConfigItem */ + void set(RsChatMsgItem *ci, const RsPeerId &peerId, uint32_t confFlags); + /* get data from RsPrivateChatMsgConfigItem to RsChatMsgItem */ + void get(RsChatMsgItem *ci); - RsPeerId configPeerId; - uint32_t chatFlags; - uint32_t configFlags; - uint32_t sendTime; - std::string message; - uint32_t recvTime; + RsPeerId configPeerId; + uint32_t chatFlags; + uint32_t configFlags; + uint32_t sendTime; + std::string message; + uint32_t recvTime; }; class RsPrivateChatDistantInviteConfigItem: public RsChatItem { @@ -413,6 +416,126 @@ class RsChatDHPublicKeyItem: public RsChatItem const RsChatDHPublicKeyItem& operator=(const RsChatDHPublicKeyItem&) { return *this ;} }; + +struct PrivateOugoingMapItem : RsChatItem +{ + PrivateOugoingMapItem() : RsChatItem(RS_PKT_SUBTYPE_OUTGOING_MAP) {} + + uint32_t serial_size() + { + uint32_t s = 8; /* header */ + s += 4; // number of entries + for( auto entry : store ) + { + s += 8; // key size + s += entry.second.serial_size(); + } + return s; + } + bool serialise(void* data, uint32_t& pktsize) + { + uint32_t tlvsize = serial_size(); + uint32_t offset = 0; + + if (pktsize < tlvsize) return false; /* not enough space */ + + pktsize = tlvsize; + + bool ok = true; + + ok = ok && setRsItemHeader(data, tlvsize, PacketId(), tlvsize) + && (offset += 8); + + ok = ok && setRawUInt32(data, tlvsize, &offset, store.size()); + + for( auto entry : store ) + { + ok = ok && setRawUInt64(data, tlvsize, &offset, entry.first); + + uint8_t* hdrPtr = static_cast(data) + offset; + uint32_t tmpsize = entry.second.serial_size(); + ok = ok && entry.second.serialise(hdrPtr, tmpsize); + } + + if (offset != tlvsize) + { + ok = false; + std::cerr << "PrivateOugoingMapItem::serialise() Size Error!" + << std::endl; + } + + return ok; + } + PrivateOugoingMapItem* deserialise(const uint8_t* data, uint32_t& pktsize) + { + /* get the type and size */ + uint8_t* dataPtr = const_cast(data); + uint32_t rstype = getRsItemId(dataPtr); + uint32_t rssize = getRsItemSize(dataPtr); + + uint32_t offset = 0; + + if ((RS_PKT_VERSION_SERVICE != getRsItemVersion(rstype)) || + (RS_SERVICE_TYPE_CHAT != getRsItemService(rstype)) || + (RS_PKT_SUBTYPE_OUTGOING_MAP != getRsItemSubType(rstype)) + ) return NULL; /* wrong type */ + + if (pktsize < rssize) return NULL; /* check size not enough data */ + + /* set the packet length */ + pktsize = rssize; + + bool ok = true; + + /* ready to load */ + PrivateOugoingMapItem* item = new PrivateOugoingMapItem(); + + /* skip the header */ + offset += 8; + + // get map size first */ + uint32_t s = 0; + ok = ok && getRawUInt32(dataPtr, rssize, &offset, &s); + + for(uint32_t i=0; i(data); hdrPtr += offset; + uint32_t tmpSize = getRsItemSize(hdrPtr); + RsChatMsgItem msgItem(hdrPtr, tmpSize); + item->store.insert(std::make_pair(msgId, msgItem)); + } + + if (offset != rssize) + { + /* error */ + std::cerr << "(EE) size error in packet deserialisation: p3MsgItem," + << " subtype " << getRsItemSubType(rstype) << ". offset=" + << offset << " != rssize=" << rssize << std::endl; + delete item; + return NULL; + } + + if (!ok) + { + std::cerr << "(EE) size error in packet deserialisation: p3MsgItem," + << " subtype " << getRsItemSubType(rstype) << std::endl; + delete item; + return NULL; + } + + return item; + } + + virtual std::ostream& print(std::ostream &out, uint16_t /*indent*/ = 0) + { return out << "PrivateOugoingMapItem store size: " << store.size(); } + + std::map store; +}; + class RsChatSerialiser: public RsSerialType { public: diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index ee2853502..2b6c8f9d9 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -1511,7 +1511,8 @@ int RsServer::StartupRetroShare() mDisc = new p3discovery2(mPeerMgr, mLinkMgr, mNetMgr, serviceCtrl); mHeart = new p3heartbeat(serviceCtrl, pqih); msgSrv = new p3MsgService( serviceCtrl, mGxsIdService, *mGxsMails ); - chatSrv = new p3ChatService(serviceCtrl,mGxsIdService, mLinkMgr, mHistoryMgr); + chatSrv = new p3ChatService( serviceCtrl,mGxsIdService, mLinkMgr, + mHistoryMgr, *mGxsMails ); mStatusSrv = new p3StatusService(serviceCtrl); #ifdef ENABLE_GROUTER diff --git a/libretroshare/src/serialiser/rsgxsmailitems.h b/libretroshare/src/serialiser/rsgxsmailitems.h index 61545fbb5..e9c565d83 100644 --- a/libretroshare/src/serialiser/rsgxsmailitems.h +++ b/libretroshare/src/serialiser/rsgxsmailitems.h @@ -29,9 +29,10 @@ /// Subservices identifiers (like port for TCP) enum class GxsMailSubServices : uint16_t { - UNKNOWN = 0, - TEST_SERVICE = 1, - P3_MSG_SERVICE = 2 + UNKNOWN = 0, + TEST_SERVICE = 1, + P3_MSG_SERVICE = 2, + P3_CHAT_SERVICE = 3 }; /// Values must fit into uint8_t From 0f1106fd8f69077fb805f947c8f8de745fe948ab Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Tue, 28 Feb 2017 01:19:18 +0100 Subject: [PATCH 26/35] PrivateOugoingMapItem fix offset calculation --- libretroshare/src/chat/rschatitems.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/libretroshare/src/chat/rschatitems.h b/libretroshare/src/chat/rschatitems.h index b047f221f..7acd7e44f 100644 --- a/libretroshare/src/chat/rschatitems.h +++ b/libretroshare/src/chat/rschatitems.h @@ -454,7 +454,9 @@ struct PrivateOugoingMapItem : RsChatItem uint8_t* hdrPtr = static_cast(data) + offset; uint32_t tmpsize = entry.second.serial_size(); - ok = ok && entry.second.serialise(hdrPtr, tmpsize); + ok = ok && entry.second.serialise(hdrPtr, tmpsize) + && (offset += tmpsize); + } if (offset != tlvsize) @@ -505,7 +507,7 @@ struct PrivateOugoingMapItem : RsChatItem uint8_t* hdrPtr = const_cast(data); hdrPtr += offset; uint32_t tmpSize = getRsItemSize(hdrPtr); - RsChatMsgItem msgItem(hdrPtr, tmpSize); + RsChatMsgItem msgItem(hdrPtr, tmpSize); offset+= tmpSize; item->store.insert(std::make_pair(msgId, msgItem)); } @@ -531,7 +533,10 @@ struct PrivateOugoingMapItem : RsChatItem } virtual std::ostream& print(std::ostream &out, uint16_t /*indent*/ = 0) - { return out << "PrivateOugoingMapItem store size: " << store.size(); } + { + return out << "PrivateOugoingMapItem store size: " << store.size() + << std::endl; + } std::map store; }; From 953b70fbe4bda9d376c7dda2512309e0edb31dac Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Wed, 1 Mar 2017 23:07:53 +0100 Subject: [PATCH 27/35] Improve async distant chat, fix chat msg receiving DistantChatService::initiateDistantChatConnexion(...) made notification message optional (enabled by default) p3ChatService removed duplicion avoidance as it is not necessary p3ChatService::sendStatusString(...) send status only if peer is online protect p3ChatService::mDistantGxsMap with mutex as operation on it may be done by different threads p3ChatService::receiveGxsMai(...) set chat message item peer id with distant tunnel id, so it is recognized as a distant message later made p3GxsTunnelService::makeGxsTunnelId(...) static as it need no access to this, now it can be used easier by other components rename RsGxsMailItem::recipientsHint to recipientHint as for now only one recipient is possible (TODO: update documentation too) GxsMailsClient::receiveGxsMail(...) changed paramethers for better abstracion, now destination id is passed too because it is usually a very useful information ChatWidget some adaptation to async chat, a couple of method have been deprecated too PopupDistantChatDialog::updateDisplay(...) adapt message shown to the user to the new async chat paradigm (TODO: need review) --- libretroshare/src/chat/distantchat.cc | 28 ++-- libretroshare/src/chat/distantchat.h | 13 +- libretroshare/src/chat/p3chatservice.cc | 149 ++++++++---------- libretroshare/src/chat/p3chatservice.h | 31 ++-- libretroshare/src/gxstunnel/p3gxstunnel.cc | 25 +-- libretroshare/src/gxstunnel/p3gxstunnel.h | 6 +- libretroshare/src/serialiser/rsgxsmailitems.h | 14 +- libretroshare/src/services/p3gxsmails.cpp | 31 ++-- libretroshare/src/services/p3gxsmails.h | 9 +- libretroshare/src/services/p3msgservice.cc | 9 +- libretroshare/src/services/p3msgservice.h | 3 +- retroshare-gui/src/gui/chat/ChatWidget.cpp | 17 +- retroshare-gui/src/gui/chat/ChatWidget.h | 8 +- .../src/gui/chat/PopupDistantChatDialog.cpp | 81 ++++++---- 14 files changed, 212 insertions(+), 212 deletions(-) diff --git a/libretroshare/src/chat/distantchat.cc b/libretroshare/src/chat/distantchat.cc index 70fb88d8c..236fe5eca 100644 --- a/libretroshare/src/chat/distantchat.cc +++ b/libretroshare/src/chat/distantchat.cc @@ -243,7 +243,9 @@ void DistantChatService::markDistantChatAsClosed(const DistantChatPeerId& dcpid) mDistantChatContacts.erase(it) ; } -bool DistantChatService::initiateDistantChatConnexion(const RsGxsId& to_gxs_id, const RsGxsId& from_gxs_id, DistantChatPeerId& dcpid, uint32_t& error_code) +bool DistantChatService::initiateDistantChatConnexion( + const RsGxsId& to_gxs_id, const RsGxsId& from_gxs_id, + DistantChatPeerId& dcpid, uint32_t& error_code, bool notify ) { RsGxsTunnelId tunnel_id ; @@ -259,17 +261,19 @@ bool DistantChatService::initiateDistantChatConnexion(const RsGxsId& to_gxs_id, error_code = RS_DISTANT_CHAT_ERROR_NO_ERROR ; - // Make a self message to raise the chat window - - RsChatMsgItem *item = new RsChatMsgItem; - item->message = "[Starting distant chat. Please wait for secure tunnel to be established]" ; - item->chatFlags = RS_CHAT_FLAG_PRIVATE ; - item->sendTime = time(NULL) ; - item->PeerId(RsPeerId(tunnel_id)) ; - handleRecvChatMsgItem(item) ; - - delete item ; // item is replaced by NULL if partial, but this is not the case here. - + if(notify) + { + // Make a self message to raise the chat window + RsChatMsgItem *item = new RsChatMsgItem; + item->message = "[Starting distant chat. Please wait for secure tunnel"; + item->message += " to be established]"; + item->chatFlags = RS_CHAT_FLAG_PRIVATE; + item->sendTime = time(NULL); + item->PeerId(RsPeerId(tunnel_id)); + handleRecvChatMsgItem(item); + delete item ; + } + return true ; } diff --git a/libretroshare/src/chat/distantchat.h b/libretroshare/src/chat/distantchat.h index 444817c06..b177e6029 100644 --- a/libretroshare/src/chat/distantchat.h +++ b/libretroshare/src/chat/distantchat.h @@ -45,10 +45,15 @@ public: bool processLoadListItem(const RsItem *item) ; void addToSaveList(std::list& list) const; - // Creates the invite if the public key of the distant peer is available. - // Om success, stores the invite in the map above, so that we can respond to tunnel requests. - // - bool initiateDistantChatConnexion(const RsGxsId& to_gxs_id, const RsGxsId &from_gxs_id, DistantChatPeerId& dcpid, uint32_t &error_code) ; + /** + * Creates the invite if the public key of the distant peer is available. + * On success, stores the invite in the map above, so that we can respond + * to tunnel requests. */ + bool initiateDistantChatConnexion( const RsGxsId& to_gxs_id, + const RsGxsId &from_gxs_id, + DistantChatPeerId& dcpid, + uint32_t &error_code, + bool notify = true ); bool closeDistantChatConnexion(const DistantChatPeerId &tunnel_id) ; // Sets flags to only allow connexion from some people. diff --git a/libretroshare/src/chat/p3chatservice.cc b/libretroshare/src/chat/p3chatservice.cc index d85ecc7e2..d03a0c022 100644 --- a/libretroshare/src/chat/p3chatservice.cc +++ b/libretroshare/src/chat/p3chatservice.cc @@ -59,8 +59,9 @@ p3ChatService::p3ChatService( p3ServiceControl *sc, p3IdService *pids, DistributedChatService(getServiceInfo().mServiceType, sc, historyMgr,pids), mChatMtx("p3ChatService"), mServiceCtrl(sc), mLinkMgr(lm), mHistoryMgr(historyMgr), _own_avatar(NULL), - _serializer(new RsChatSerialiser()), mGxsTransport(gxsMailService), - recentlyReceivedMutex("p3ChatService recently received mutex") + _serializer(new RsChatSerialiser()), + mDGMutex("p3ChatService distant id - gxs id map mutex"), + mGxsTransport(gxsMailService) { addSerialType(_serializer); mGxsTransport.registerGxsMailsClient( GxsMailSubServices::P3_CHAT_SERVICE, @@ -76,8 +77,6 @@ int p3ChatService::tick() DistributedChatService::flush(); - cleanListOfReceivedMessageHashes(); - return 0; } @@ -203,37 +202,38 @@ void p3ChatService::sendGroupChatStatusString(const std::string& status_string) } } -void p3ChatService::sendStatusString(const ChatId& id , const std::string& status_string) +void p3ChatService::sendStatusString( const ChatId& id, + const std::string& status_string ) { - if(id.isLobbyId()) - sendLobbyStatusString(id.toLobbyId(),status_string) ; - else if(id.isBroadcast()) - sendGroupChatStatusString(status_string); - else if(id.isPeerId() || id.isDistantChatId()) - { - RsChatStatusItem *cs = new RsChatStatusItem ; + if(id.isLobbyId()) sendLobbyStatusString(id.toLobbyId(),status_string); + else if(id.isBroadcast()) sendGroupChatStatusString(status_string); + else if(id.isPeerId() || id.isDistantChatId()) + { + RsPeerId vpid; + if(id.isDistantChatId()) vpid = RsPeerId(id.toDistantChatId()); + else vpid = id.toPeerId(); - cs->status_string = status_string ; - cs->flags = RS_CHAT_FLAG_PRIVATE ; - RsPeerId vpid; - if(id.isDistantChatId()) - vpid = RsPeerId(id.toDistantChatId()); - else - vpid = id.toPeerId(); - - cs->PeerId(vpid); + if(isOnline(vpid)) + { + RsChatStatusItem *cs = new RsChatStatusItem; + + cs->status_string = status_string; + cs->flags = RS_CHAT_FLAG_PRIVATE; + cs->PeerId(vpid); #ifdef CHAT_DEBUG - std::cerr << "sending chat status packet:" << std::endl ; - cs->print(std::cerr) ; + std::cerr << "sending chat status packet:" << std::endl; + cs->print(std::cerr); #endif - sendChatItem(cs); - } - else - { - std::cerr << "p3ChatService::sendStatusString() Error: chat id of this type is not handled, is it empty?" << std::endl; - return; - } + sendChatItem(cs); + } + } + else + { + std::cerr << "p3ChatService::sendStatusString() Error: chat id of this " + << "type is not handled, is it empty?" << std::endl; + return; + } } void p3ChatService::clearChatLobby(const ChatId& id) @@ -339,7 +339,8 @@ bool p3ChatService::sendChat(ChatId destination, std::string msg) if(destination.isDistantChatId()) { - DEPMap::const_iterator it = + RS_STACK_MUTEX(mDGMutex); + DIDEMap::const_iterator it = mDistantGxsMap.find(destination.toDistantChatId()); if(it != mDistantGxsMap.end()) { @@ -687,31 +688,50 @@ bool p3ChatService::checkForMessageSecurity(RsChatMsgItem *ci) return true ; } -bool p3ChatService::initiateDistantChatConnexion( - const RsGxsId& to_gxs_id, const RsGxsId& from_gxs_id, - DistantChatPeerId& pid, uint32_t& error_code ) +bool p3ChatService::initiateDistantChatConnexion( const RsGxsId& to_gxs_id, + const RsGxsId& from_gxs_id, + DistantChatPeerId& pid, + uint32_t& error_code, + bool notify ) { if(DistantChatService::initiateDistantChatConnexion( to_gxs_id, from_gxs_id, pid, - error_code )) + error_code, notify )) { + RS_STACK_MUTEX(mDGMutex); DistantEndpoints ep; ep.from = from_gxs_id; ep.to = to_gxs_id; - mDistantGxsMap.insert(DEPMap::value_type(pid, ep)); + mDistantGxsMap.insert(DIDEMap::value_type(pid, ep)); return true; } return false; } -bool p3ChatService::receiveGxsMail(const RsGxsMailItem&, const uint8_t* data, uint32_t dataSize) +bool p3ChatService::receiveGxsMail( const RsGxsId& authorId, + const RsGxsId& recipientId, + const uint8_t* data, uint32_t dataSize ) { - RsChatMsgItem* item = new RsChatMsgItem( const_cast(data), - dataSize ); - handleRecvChatMsgItem(item); - delete item; - return true; + DistantChatPeerId pid; + uint32_t error_code; + if(initiateDistantChatConnexion( + authorId, recipientId, pid, error_code, false )) + { + RsChatMsgItem* item = new RsChatMsgItem( const_cast(data), + dataSize ); + RsPeerId rd(p3GxsTunnelService::makeGxsTunnelId(authorId, recipientId)); + item->PeerId(rd); + handleRecvChatMsgItem(item); + delete item; + return true; + } + + std::cerr << "p3ChatService::receiveGxsMail(...) (EE) failed initiating" + << " distant chat connection error: "<< error_code + << std::endl; + return false; } -bool p3ChatService::notifySendMailStatus(const RsGxsMailItem& originalMessage, GxsMailStatus status) +bool p3ChatService::notifySendMailStatus( const RsGxsMailItem& originalMessage, + GxsMailStatus status ) { if ( status != GxsMailStatus::RECEIPT_RECEIVED ) return true; @@ -740,29 +760,6 @@ bool p3ChatService::notifySendMailStatus(const RsGxsMailItem& originalMessage, G bool p3ChatService::handleRecvChatMsgItem(RsChatMsgItem *& ci) { - time_t now = time(NULL); - - { // Check for duplicates - uint32_t sz = ci->serial_size(); - std::vector srz; srz.resize(sz); - ci->serialise(&srz[0], sz); - Sha1CheckSum hash = RsDirUtil::sha1sum(&srz[0], sz); - { - RS_STACK_MUTEX(recentlyReceivedMutex); - if( mRecentlyReceivedMessageHashes.find(hash) != - mRecentlyReceivedMessageHashes.end() ) - { - std::cerr << "p3ChatService::handleRecvChatMsgItem(...) (II) " - << "receiving distant message of hash " << hash - << " more than once. Probably it has arrived before " - << "by other means." << std::endl; - delete ci; ci=NULL; - return true; - } - mRecentlyReceivedMessageHashes[hash] = now; - } - } - std::string name; uint32_t popupChatFlag = RS_POPUP_CHAT; @@ -840,7 +837,7 @@ bool p3ChatService::handleRecvChatMsgItem(RsChatMsgItem *& ci) } } - ci->recvTime = now; + ci->recvTime = time(NULL); ChatMessage cm; initChatMessage(ci, cm); @@ -1169,24 +1166,6 @@ RsChatStatusItem *p3ChatService::makeOwnCustomStateStringItem() return ci ; } -void p3ChatService::cleanListOfReceivedMessageHashes() -{ - RS_STACK_MUTEX(recentlyReceivedMutex); - - time_t now = time(NULL); - - for( auto it = mRecentlyReceivedMessageHashes.begin(); - it != mRecentlyReceivedMessageHashes.end(); ) - if( now > RECENTLY_RECEIVED_INTERVAL + it->second ) - { - std::cerr << "p3MsgService(): cleanListOfReceivedMessageHashes(" - << "). Removing old hash " << it->first << ", aged " - << now - it->second << " secs ago." << std::endl; - - it = mRecentlyReceivedMessageHashes.erase(it); - } - else ++it; -} RsChatAvatarItem *p3ChatService::makeOwnAvatarItem() { RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ diff --git a/libretroshare/src/chat/p3chatservice.h b/libretroshare/src/chat/p3chatservice.h index 365ddb4a9..993dc1d94 100644 --- a/libretroshare/src/chat/p3chatservice.h +++ b/libretroshare/src/chat/p3chatservice.h @@ -95,11 +95,11 @@ struct p3ChatService : */ bool sendPrivateChat(const RsPeerId &id, const std::string &msg); - /*! - * can be used to send 'immediate' status msgs, these status updates are meant for immediate use by peer (not saved by rs) - * e.g currently used to update user when a peer 'is typing' during a chat - */ - void sendStatusString(const ChatId& id,const std::string& status_str) ; + /** + * can be used to send 'immediate' status msgs, these status updates are + * meant for immediate use by peer (not saved by rs) e.g currently used to + * update user when a peer 'is typing' during a chat */ + void sendStatusString( const ChatId& id, const std::string& status_str ); /** * @brief clearChatLobby: Signal chat was cleared by GUI. @@ -168,10 +168,12 @@ struct p3ChatService : virtual bool initiateDistantChatConnexion( const RsGxsId& to_gxs_id, const RsGxsId& from_gxs_id, DistantChatPeerId &pid, - uint32_t& error_code ); + uint32_t& error_code, + bool notify = true ); /// @see GxsMailsClient::receiveGxsMail(...) - virtual bool receiveGxsMail( const RsGxsMailItem& /*originalMessage*/, + virtual bool receiveGxsMail( const RsGxsId& authorId, + const RsGxsId& recipientId, const uint8_t* data, uint32_t dataSize ); /// @see GxsMailsClient::notifySendMailStatus(...) @@ -256,7 +258,7 @@ private: AvatarInfo *_own_avatar ; std::map _avatars ; - std::map _pendingPartialMessages ; + std::map _pendingPartialMessages; std::string _custom_status_string ; std::map _state_strings ; @@ -264,16 +266,11 @@ private: RsChatSerialiser *_serializer; struct DistantEndpoints { RsGxsId from; RsGxsId to; }; - typedef std::map DEPMap; - DEPMap mDistantGxsMap; - p3GxsMails& mGxsTransport; + typedef std::map DIDEMap; + DIDEMap mDistantGxsMap; + RsMutex mDGMutex; - /** As we have multiple backends duplicates are possible, keep track of - * recently received messages hashes for at least 2h to avoid them */ - const static uint32_t RECENTLY_RECEIVED_INTERVAL = 2*3600; - std::map mRecentlyReceivedMessageHashes; - RsMutex recentlyReceivedMutex; - void cleanListOfReceivedMessageHashes(); + p3GxsMails& mGxsTransport; }; class p3ChatService::StateStringInfo diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.cc b/libretroshare/src/gxstunnel/p3gxstunnel.cc index 3ad4198a9..2d2da50dc 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.cc +++ b/libretroshare/src/gxstunnel/p3gxstunnel.cc @@ -1023,7 +1023,8 @@ void p3GxsTunnelService::handleRecvDHPublicKey(RsGxsTunnelDHPublicKeyItem *item) // Note: for some obscure reason, the typedef does not work here. Looks like a compiler error. So I use the primary type. -GXSTunnelId p3GxsTunnelService::makeGxsTunnelId(const RsGxsId &own_id, const RsGxsId &distant_id) const // creates a unique ID from two GXS ids. +/*static*/ GXSTunnelId p3GxsTunnelService::makeGxsTunnelId( + const RsGxsId &own_id, const RsGxsId &distant_id ) { unsigned char mem[RsGxsId::SIZE_IN_BYTES * 2] ; @@ -1240,18 +1241,20 @@ bool p3GxsTunnelService::locked_sendEncryptedTunnelData(RsGxsTunnelItem *item) std::map::iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; - if(it == _gxs_tunnel_contacts.end()) - { + if(it == _gxs_tunnel_contacts.end()) + { #ifdef DEBUG_GXS_TUNNEL - std::cerr << " Cannot find contact key info for tunnel id " << tunnel_id << ". Cannot send message!" << std::endl; + std::cerr << " Cannot find contact key info for tunnel id " + << tunnel_id << ". Cannot send message!" << std::endl; #endif - return false; - } - if(it->second.status != RS_GXS_TUNNEL_STATUS_CAN_TALK) - { - std::cerr << "(EE) Cannot talk to tunnel id " << tunnel_id << ". Tunnel status is: " << it->second.status << std::endl; - return false; - } + return false; + } + if(it->second.status != RS_GXS_TUNNEL_STATUS_CAN_TALK) + { + std::cerr << "(EE) Cannot talk to tunnel id " << tunnel_id + << ". Tunnel status is: " << it->second.status << std::endl; + return false; + } it->second.total_sent += rssize ; // counts the size of clear data that is sent diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.h b/libretroshare/src/gxstunnel/p3gxstunnel.h index 9a2481623..8d4ebfefc 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.h +++ b/libretroshare/src/gxstunnel/p3gxstunnel.h @@ -232,7 +232,6 @@ private: bool locked_initDHSessionKey(DH *&dh); TurtleVirtualPeerId virtualPeerIdFromHash(const TurtleFileHash& hash) ; // ... and to a hash for p3turtle - RsGxsTunnelId makeGxsTunnelId(const RsGxsId &own_id, const RsGxsId &distant_id) const; // creates a unique ID from two GXS ids. // item handling @@ -256,5 +255,10 @@ private: std::map mRegisteredServices ; void debug_dump(); + +public: + /// creates a unique tunnel ID from two GXS ids. + static RsGxsTunnelId makeGxsTunnelId( const RsGxsId &own_id, + const RsGxsId &distant_id ); }; diff --git a/libretroshare/src/serialiser/rsgxsmailitems.h b/libretroshare/src/serialiser/rsgxsmailitems.h index e9c565d83..ac255b3f5 100644 --- a/libretroshare/src/serialiser/rsgxsmailitems.h +++ b/libretroshare/src/serialiser/rsgxsmailitems.h @@ -131,9 +131,9 @@ struct RsGxsMailItem : RsGxsMailBaseItem * mail is directed to the actual recipient as the "apparently" * corresponding hint may be fruit of a "luky" salting of another id. */ - RsGxsId recipientsHint; + RsGxsId recipientHint; void inline saltRecipientHint(const RsGxsId& salt) - { recipientsHint = recipientsHint | salt; } + { recipientHint = recipientHint | salt; } /** * @brief maybeRecipient given an id and an hint check if they match @@ -141,7 +141,7 @@ struct RsGxsMailItem : RsGxsMailBaseItem * @return true if the id may be recipient of the hint, false otherwise */ bool inline maybeRecipient(const RsGxsId& id) const - { return (~id|recipientsHint) == allRecipientsHint; } + { return (~id|recipientHint) == allRecipientsHint; } const static RsGxsId allRecipientsHint; @@ -153,7 +153,7 @@ struct RsGxsMailItem : RsGxsMailBaseItem { return RsGxsMailBaseItem::size() + 1 + // cryptoType - recipientsHint.serial_size() + + recipientHint.serial_size() + payload.size(); } bool serialize(uint8_t* data, uint32_t size, uint32_t& offset) const @@ -162,7 +162,7 @@ struct RsGxsMailItem : RsGxsMailBaseItem ok = ok && RsGxsMailBaseItem::serialize(data, size, offset); ok = ok && setRawUInt8( data, size, &offset, static_cast(cryptoType) ); - ok = ok && recipientsHint.serialise(data, size, offset); + ok = ok && recipientHint.serialise(data, size, offset); uint32_t psz = payload.size(); ok = ok && memcpy(data+offset, &payload[0], psz); offset += psz; @@ -181,7 +181,7 @@ struct RsGxsMailItem : RsGxsMailBaseItem uint8_t crType; ok = ok && getRawUInt8(dataPtr, rssize, &roffset, &crType); cryptoType = static_cast(crType); - ok = ok && recipientsHint.deserialise(dataPtr, rssize, roffset); + ok = ok && recipientHint.deserialise(dataPtr, rssize, roffset); uint32_t psz = rssize - roffset; ok = ok && (payload.resize(psz), memcpy(&payload[0], data+roffset, psz)); ok = ok && (roffset += psz); @@ -193,7 +193,7 @@ struct RsGxsMailItem : RsGxsMailBaseItem { RsGxsMailBaseItem::clear(); cryptoType = RsGxsMailEncryptionMode::UNDEFINED_ENCRYPTION; - recipientsHint.clear(); + recipientHint.clear(); payload.clear(); } diff --git a/libretroshare/src/services/p3gxsmails.cpp b/libretroshare/src/services/p3gxsmails.cpp index a4957b4e7..06acdce96 100644 --- a/libretroshare/src/services/p3gxsmails.cpp +++ b/libretroshare/src/services/p3gxsmails.cpp @@ -262,7 +262,7 @@ void p3GxsMails::service_tick() << msg->meta.mMsgId << " with cryptoType: " << static_cast(msg->cryptoType) - << " recipientHint: " << msg->recipientsHint + << " recipientHint: " << msg->recipientHint << " mailId: "<< msg->mailId << " payload.size(): " << msg->payload.size() << std::endl; @@ -423,8 +423,10 @@ bool p3GxsMails::handleEcryptedMail(const RsGxsMailItem* mail) getRawUInt16(&mail->payload[0], mail->payload.size(), &off, &csri); std::cerr << "service: " << csri << " got CLEAR_TEXT mail!" << std::endl; - return dispatchDecryptedMail( mail, &mail->payload[0], - mail->payload.size() ); + /* As we cannot verify recipient without encryption, just pass the hint + * as recipient */ + return dispatchDecryptedMail( mail->meta.mAuthorId, mail->recipientHint, + &mail->payload[0], mail->payload.size() ); } case RsGxsMailEncryptionMode::RSA: { @@ -432,14 +434,16 @@ bool p3GxsMails::handleEcryptedMail(const RsGxsMailItem* mail) for( std::set::const_iterator it = decryptIds.begin(); it != decryptIds.end(); ++it ) { + const RsGxsId& decryptId(*it); uint8_t* decrypted_data = NULL; uint32_t decrypted_data_size = 0; uint32_t decryption_error; if( idService.decryptData( &mail->payload[0], mail->payload.size(), decrypted_data, - decrypted_data_size, *it, + decrypted_data_size, decryptId, decryption_error ) ) - ok = ok && dispatchDecryptedMail( mail, decrypted_data, + ok = ok && dispatchDecryptedMail( mail->meta.mAuthorId, + decryptId, decrypted_data, decrypted_data_size ); free(decrypted_data); } @@ -452,7 +456,8 @@ bool p3GxsMails::handleEcryptedMail(const RsGxsMailItem* mail) } } -bool p3GxsMails::dispatchDecryptedMail( const RsGxsMailItem* received_msg, +bool p3GxsMails::dispatchDecryptedMail( const RsGxsId& authorId, + const RsGxsId& decryptId, const uint8_t* decrypted_data, uint32_t decrypted_data_size ) { @@ -486,16 +491,16 @@ bool p3GxsMails::dispatchDecryptedMail( const RsGxsMailItem* received_msg, std::vector rcct; rcct.push_back(receipt); RsGenExchange::notifyNewMessages(rcct); - GxsMailsClient* reecipientService = NULL; + GxsMailsClient* recipientService = NULL; { RS_STACK_MUTEX(servClientsMutex); - reecipientService = servClients[rsrvc]; + recipientService = servClients[rsrvc]; } - if(reecipientService) - return reecipientService->receiveGxsMail( *received_msg, - &decrypted_data[offset], - decrypted_data_size-offset ); + if(recipientService) + return recipientService->receiveGxsMail( authorId, decryptId, + &decrypted_data[offset], + decrypted_data_size-offset ); else { std::cerr << "p3GxsMails::dispatchReceivedMail(...) " @@ -625,7 +630,7 @@ void p3GxsMails::processOutgoingRecord(OutgoingRecord& pr) << pr.recipient << " with cryptoType: " << static_cast(pr.mailItem.cryptoType) - << " recipientHint: " << pr.mailItem.recipientsHint + << " recipientHint: " << pr.mailItem.recipientHint << " receiptId: " << pr.mailItem.mailId << " payload size: " << pr.mailItem.payload.size() << std::endl; diff --git a/libretroshare/src/services/p3gxsmails.h b/libretroshare/src/services/p3gxsmails.h index 7941f8aa3..1a9545e66 100644 --- a/libretroshare/src/services/p3gxsmails.h +++ b/libretroshare/src/services/p3gxsmails.h @@ -34,12 +34,14 @@ struct GxsMailsClient { /** * This will be called by p3GxsMails to dispatch mails to the subservice - * @param originalMessage message as received from GXS backend (encrypted) + * @param authorId message sender + * @param decryptId recipient id * @param data buffer containing the decrypted data * @param dataSize size of the buffer * @return true if dispatching goes fine, false otherwise */ - virtual bool receiveGxsMail( const RsGxsMailItem& originalMessage, + virtual bool receiveGxsMail( const RsGxsId& authorId, + const RsGxsId& recipientId, const uint8_t* data, uint32_t dataSize ) = 0; /** @@ -242,7 +244,8 @@ private: bool handleEcryptedMail(const RsGxsMailItem* mail); /// Dispatch the message to the recipient service - bool dispatchDecryptedMail( const RsGxsMailItem* received_msg, + bool dispatchDecryptedMail( const RsGxsId& authorId, + const RsGxsId& decryptId, const uint8_t* decrypted_data, uint32_t decrypted_data_size ); diff --git a/libretroshare/src/services/p3msgservice.cc b/libretroshare/src/services/p3msgservice.cc index 6da7a91b7..7d33b2235 100644 --- a/libretroshare/src/services/p3msgservice.cc +++ b/libretroshare/src/services/p3msgservice.cc @@ -1990,11 +1990,12 @@ uint32_t p3MsgService::getDistantMessagingPermissionFlags() return mDistantMessagePermissions ; } -bool p3MsgService::receiveGxsMail( const RsGxsMailItem& originalMessage, +bool p3MsgService::receiveGxsMail( const RsGxsId& authorId, + const RsGxsId& recipientId, const uint8_t* data, uint32_t dataSize ) { - std::cout << "p3MsgService::receiveGxsMail(" << originalMessage.mailId - << ",, " << dataSize << ")" << std::endl; + std::cout << "p3MsgService::receiveGxsMail(" << authorId + << ", " << recipientId << ", " << dataSize << ")" << std::endl; Sha1CheckSum hash = RsDirUtil::sha1sum(data, dataSize); @@ -2029,7 +2030,7 @@ bool p3MsgService::receiveGxsMail( const RsGxsMailItem& originalMessage, msg_item->msgFlags &= ~RS_MSG_FLAGS_PARTIAL; // hack to pass on GXS id. - msg_item->PeerId(RsPeerId(originalMessage.meta.mAuthorId)); + msg_item->PeerId(RsPeerId(authorId)); handleIncomingItem(msg_item); } else diff --git a/libretroshare/src/services/p3msgservice.h b/libretroshare/src/services/p3msgservice.h index 8bfd1b89a..8846c3f9a 100644 --- a/libretroshare/src/services/p3msgservice.h +++ b/libretroshare/src/services/p3msgservice.h @@ -136,7 +136,8 @@ struct p3MsgService : uint32_t getDistantMessagingPermissionFlags() ; /// @see GxsMailsClient::receiveGxsMail(...) - virtual bool receiveGxsMail( const RsGxsMailItem& originalMessage, + virtual bool receiveGxsMail( const RsGxsId& authorId, + const RsGxsId& recipientId, const uint8_t* data, uint32_t dataSize ); /// @see GxsMailsClient::notifySendMailStatus(...) diff --git a/retroshare-gui/src/gui/chat/ChatWidget.cpp b/retroshare-gui/src/gui/chat/ChatWidget.cpp index cfde6a028..f7de21ff1 100644 --- a/retroshare-gui/src/gui/chat/ChatWidget.cpp +++ b/retroshare-gui/src/gui/chat/ChatWidget.cpp @@ -70,7 +70,7 @@ *****/ ChatWidget::ChatWidget(QWidget *parent) : - QWidget(parent), sendingBlocked(false), ui(new Ui::ChatWidget) + QWidget(parent), ui(new Ui::ChatWidget) { ui->setupUi(this); @@ -413,18 +413,9 @@ ChatWidget::ChatType ChatWidget::chatType() return CHATTYPE_UNKNOWN; } -void ChatWidget::blockSending(QString msg) -{ - sendingBlocked = true; - ui->sendButton->setEnabled(false); - ui->sendButton->setToolTip(msg); -} +void ChatWidget::blockSending(QString msg) { ui->sendButton->setToolTip(msg); } -void ChatWidget::unblockSending() -{ - sendingBlocked = false; - updateLenOfChatTextEdit(); -} +void ChatWidget::unblockSending() { updateLenOfChatTextEdit(); } void ChatWidget::processSettings(bool load) { @@ -1096,8 +1087,6 @@ void ChatWidget::updateStatusTyping() void ChatWidget::updateLenOfChatTextEdit() { - if(sendingBlocked) return; - QTextEdit *chatWidget = ui->chatTextEdit; QString text; RsHtml::optimizeHtml(chatWidget, text); diff --git a/retroshare-gui/src/gui/chat/ChatWidget.h b/retroshare-gui/src/gui/chat/ChatWidget.h index 174b4d777..270671af4 100644 --- a/retroshare-gui/src/gui/chat/ChatWidget.h +++ b/retroshare-gui/src/gui/chat/ChatWidget.h @@ -36,6 +36,7 @@ #include #include +#include class QAction; class QTextEdit; @@ -78,9 +79,8 @@ public: ChatId getChatId(); ChatType chatType(); - // allow/disallow sendng of messages - void blockSending(QString msg); - void unblockSending(); + RS_DEPRECATED void blockSending(QString msg); + RS_DEPRECATED void unblockSending(); bool hasNewMessages() { return newMessages; } bool isTyping() { return typing; } @@ -216,8 +216,6 @@ private: bool typing; int peerStatus; - bool sendingBlocked; - time_t lastStatusSendTime; ChatStyle chatStyle; diff --git a/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp b/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp index 4992b5ff5..6d0fe079d 100644 --- a/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp +++ b/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp @@ -104,41 +104,52 @@ void PopupDistantChatDialog::updateDisplay() QString msg; - switch(tinfo.status) - { - case RS_DISTANT_CHAT_STATUS_UNKNOWN: //std::cerr << "Unknown hash. Error!" << std::endl; - _status_label->setIcon(QIcon(IMAGE_GRY_LED)) ; - msg = tr("Chat remotely closed. Please close this window."); - _status_label->setToolTip(msg) ; - getChatWidget()->updateStatusString("%1", msg, true); - getChatWidget()->blockSending(tr("Can't send message, because there is no tunnel.")); - setPeerStatus(RS_STATUS_OFFLINE) ; - break ; - case RS_DISTANT_CHAT_STATUS_REMOTELY_CLOSED: std::cerr << "Chat remotely closed. " << std::endl; - _status_label->setIcon(QIcon(IMAGE_RED_LED)) ; - _status_label->setToolTip(QObject::tr("Distant peer has closed the chat")) ; - - getChatWidget()->updateStatusString("%1", tr("The person you're talking to has deleted the secured chat tunnel. You may remove the chat window now."), true); - getChatWidget()->blockSending(tr("Can't send message, because the chat partner deleted the secure tunnel.")); - setPeerStatus(RS_STATUS_OFFLINE) ; - - break ; - case RS_DISTANT_CHAT_STATUS_TUNNEL_DN: //std::cerr << "Tunnel asked. Waiting for reponse. " << std::endl; - _status_label->setIcon(QIcon(IMAGE_RED_LED)) ; - msg = QObject::tr("Tunnel is pending..."); - _status_label->setToolTip(msg) ; - getChatWidget()->updateStatusString("%1", msg, true); - getChatWidget()->blockSending(msg); - setPeerStatus(RS_STATUS_OFFLINE) ; - break ; - case RS_DISTANT_CHAT_STATUS_CAN_TALK: //std::cerr << "Tunnel is ok and data is transmitted." << std::endl; - _status_label->setIcon(QIcon(IMAGE_GRN_LED)) ; - msg = QObject::tr("Secured tunnel is working. You can talk!"); - _status_label->setToolTip(msg) ; - getChatWidget()->unblockSending(); - setPeerStatus(RS_STATUS_ONLINE) ; - break ; - } + switch(tinfo.status) + { + case RS_DISTANT_CHAT_STATUS_UNKNOWN: + //std::cerr << "Unknown hash. Error!" << std::endl; + _status_label->setIcon(QIcon(IMAGE_GRY_LED)); + msg = tr("Remote status unknown."); + _status_label->setToolTip(msg); + getChatWidget()->updateStatusString("%1", msg, true); + getChatWidget()->blockSending(tr( "Can't send message immediately, " + "because there is no tunnel " + "available." )); + setPeerStatus(RS_STATUS_OFFLINE); + break ; + case RS_DISTANT_CHAT_STATUS_REMOTELY_CLOSED: + std::cerr << "Chat remotely closed. " << std::endl; + _status_label->setIcon(QIcon(IMAGE_RED_LED)); + _status_label->setToolTip( + QObject::tr("Distant peer has closed the chat") ); + getChatWidget()->updateStatusString( + "%1", tr( "The person you're talking to has deleted the" + "secured chat tunnel." ), true ); + getChatWidget()->blockSending(tr( "The chat partner deleted the secure" + " tunnel, messages will be delivered" + " as soon as possible")); + setPeerStatus(RS_STATUS_OFFLINE) ; + break ; + case RS_DISTANT_CHAT_STATUS_TUNNEL_DN: + //std::cerr << "Tunnel asked. Waiting for reponse. " << std::endl; + _status_label->setIcon(QIcon(IMAGE_RED_LED)); + msg = QObject::tr( "Tunnel is pending... Messages will be delivered as" + " soon as possible" ); + _status_label->setToolTip(msg); + getChatWidget()->updateStatusString("%1", msg, true); + getChatWidget()->blockSending(msg); + setPeerStatus(RS_STATUS_OFFLINE); + break; + case RS_DISTANT_CHAT_STATUS_CAN_TALK: + //std::cerr << "Tunnel is ok and data is transmitted." << std::endl; + _status_label->setIcon(QIcon(IMAGE_GRN_LED)); + msg = QObject::tr( "Secured tunnel is working." + "Messages are delivered immediately!" ); + _status_label->setToolTip(msg); + getChatWidget()->unblockSending(); + setPeerStatus(RS_STATUS_ONLINE); + break; + } } void PopupDistantChatDialog::closeEvent(QCloseEvent *e) From 08161db43bcf4503d04b99f89bec101d418ef0f8 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Thu, 2 Mar 2017 00:08:12 +0100 Subject: [PATCH 28/35] PopupDistantChatDialog fix some strings --- retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp b/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp index 6d0fe079d..5e7c6d80e 100644 --- a/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp +++ b/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp @@ -123,8 +123,8 @@ void PopupDistantChatDialog::updateDisplay() _status_label->setToolTip( QObject::tr("Distant peer has closed the chat") ); getChatWidget()->updateStatusString( - "%1", tr( "The person you're talking to has deleted the" - "secured chat tunnel." ), true ); + "%1", tr( "The person you are talking to has deleted the" + " secured chat tunnel." ), true ); getChatWidget()->blockSending(tr( "The chat partner deleted the secure" " tunnel, messages will be delivered" " as soon as possible")); @@ -143,7 +143,7 @@ void PopupDistantChatDialog::updateDisplay() case RS_DISTANT_CHAT_STATUS_CAN_TALK: //std::cerr << "Tunnel is ok and data is transmitted." << std::endl; _status_label->setIcon(QIcon(IMAGE_GRN_LED)); - msg = QObject::tr( "Secured tunnel is working." + msg = QObject::tr( "Secured tunnel is working. " "Messages are delivered immediately!" ); _status_label->setToolTip(msg); getChatWidget()->unblockSending(); From da459c884e8ebe7d26dc872acecf4606c49d2a2f Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Thu, 2 Mar 2017 02:37:53 +0100 Subject: [PATCH 29/35] Renamed GxsMails to GxsTrans GxsTrans is a generic transport service, use more generic name trans instead of mail to avoid confusion Renamed size(...) to seria_size(...) for costistence whit the codebase Moved GxsTrans and related things to gxstrans directory Removed outdated and now uncompatible gxsmail test service Avoid expose internal items in public interface methods --- libretroshare/src/chat/p3chatservice.cc | 28 +- libretroshare/src/chat/p3chatservice.h | 24 +- .../p3gxsmails.cpp => gxstrans/p3gxstrans.cc} | 339 +++++++++--------- .../p3gxsmails.h => gxstrans/p3gxstrans.h} | 178 +++------ .../p3gxstransitems.cc} | 62 ++-- .../p3gxstransitems.h} | 132 +++---- libretroshare/src/libretroshare.pro | 6 +- libretroshare/src/rsserver/p3face-server.cc | 2 +- libretroshare/src/rsserver/p3face.h | 2 +- libretroshare/src/rsserver/rsinit.cc | 51 ++- libretroshare/src/serialiser/rsserviceids.h | 2 +- libretroshare/src/services/p3msgservice.cc | 63 ++-- libretroshare/src/services/p3msgservice.h | 24 +- retroshare.pri | 14 +- 14 files changed, 427 insertions(+), 500 deletions(-) rename libretroshare/src/{services/p3gxsmails.cpp => gxstrans/p3gxstrans.cc} (63%) rename libretroshare/src/{services/p3gxsmails.h => gxstrans/p3gxstrans.h} (59%) rename libretroshare/src/{serialiser/rsgxsmailitems.cc => gxstrans/p3gxstransitems.cc} (71%) rename libretroshare/src/{serialiser/rsgxsmailitems.h => gxstrans/p3gxstransitems.h} (71%) diff --git a/libretroshare/src/chat/p3chatservice.cc b/libretroshare/src/chat/p3chatservice.cc index d03a0c022..3f7f12d99 100644 --- a/libretroshare/src/chat/p3chatservice.cc +++ b/libretroshare/src/chat/p3chatservice.cc @@ -40,6 +40,7 @@ #include "pqi/p3historymgr.h" #include "rsserver/p3face.h" #include "services/p3idservice.h" +#include "gxstrans/p3gxstrans.h" #include "chat/p3chatservice.h" #include "serialiser/rsconfigitems.h" @@ -55,16 +56,16 @@ static const uint32_t MAX_AVATAR_JPEG_SIZE = 32767; // Maximum size p3ChatService::p3ChatService( p3ServiceControl *sc, p3IdService *pids, p3LinkMgr *lm, p3HistoryMgr *historyMgr, - p3GxsMails& gxsMailService ) : + p3GxsTrans& gxsTransService ) : DistributedChatService(getServiceInfo().mServiceType, sc, historyMgr,pids), mChatMtx("p3ChatService"), mServiceCtrl(sc), mLinkMgr(lm), mHistoryMgr(historyMgr), _own_avatar(NULL), _serializer(new RsChatSerialiser()), mDGMutex("p3ChatService distant id - gxs id map mutex"), - mGxsTransport(gxsMailService) + mGxsTransport(gxsTransService) { addSerialType(_serializer); - mGxsTransport.registerGxsMailsClient( GxsMailSubServices::P3_CHAT_SERVICE, + mGxsTransport.registerGxsTransClient( GxsTransSubServices::P3_CHAT_SERVICE, this ); } @@ -335,7 +336,7 @@ bool p3ChatService::sendChat(ChatId destination, std::string msg) // this is not very nice, because the user may think the message was send, while it is still in the queue mHistoryMgr->addMessage(message); - RsGxsMailId tId = RSRandom::random_u64(); + RsGxsTransId tId = RSRandom::random_u64(); if(destination.isDistantChatId()) { @@ -348,7 +349,7 @@ bool p3ChatService::sendChat(ChatId destination, std::string msg) uint32_t sz = ci->serial_size(); std::vector data; data.resize(sz); ci->serialise(&data[0], sz); - mGxsTransport.sendMail(tId, GxsMailSubServices::P3_CHAT_SERVICE, + mGxsTransport.sendMail(tId, GxsTransSubServices::P3_CHAT_SERVICE, de.from, de.to, &data[0], sz); } else @@ -706,9 +707,10 @@ bool p3ChatService::initiateDistantChatConnexion( const RsGxsId& to_gxs_id, return false; } -bool p3ChatService::receiveGxsMail( const RsGxsId& authorId, - const RsGxsId& recipientId, - const uint8_t* data, uint32_t dataSize ) +bool p3ChatService::receiveGxsTransMail( const RsGxsId& authorId, + const RsGxsId& recipientId, + const uint8_t* data, + uint32_t dataSize ) { DistantChatPeerId pid; uint32_t error_code; @@ -724,22 +726,22 @@ bool p3ChatService::receiveGxsMail( const RsGxsId& authorId, return true; } - std::cerr << "p3ChatService::receiveGxsMail(...) (EE) failed initiating" + std::cerr << __PRETTY_FUNCTION__ << " (EE) failed initiating" << " distant chat connection error: "<< error_code << std::endl; return false; } -bool p3ChatService::notifySendMailStatus( const RsGxsMailItem& originalMessage, - GxsMailStatus status ) +bool p3ChatService::notifyGxsTransSendStatus(RsGxsTransId mailId, + GxsTransSendStatus status ) { - if ( status != GxsMailStatus::RECEIPT_RECEIVED ) return true; + if ( status != GxsTransSendStatus::RECEIPT_RECEIVED ) return true; bool changed = false; { RS_STACK_MUTEX(mChatMtx); - auto it = privateOutgoingMap.find(originalMessage.mailId); + auto it = privateOutgoingMap.find(mailId); if( it != privateOutgoingMap.end() ) { privateOutgoingMap.erase(it); diff --git a/libretroshare/src/chat/p3chatservice.h b/libretroshare/src/chat/p3chatservice.h index 993dc1d94..f7320f33c 100644 --- a/libretroshare/src/chat/p3chatservice.h +++ b/libretroshare/src/chat/p3chatservice.h @@ -37,7 +37,7 @@ #include "chat/distantchat.h" #include "chat/distributedchat.h" #include "retroshare/rsmsgs.h" -#include "services/p3gxsmails.h" +#include "gxstrans/p3gxstrans.h" #include "util/rsdeprecate.h" class p3ServiceControl; @@ -55,10 +55,10 @@ typedef RsPeerId ChatLobbyVirtualPeerId ; */ struct p3ChatService : p3Service, DistantChatService, DistributedChatService, p3Config, - pqiServiceMonitor, GxsMailsClient + pqiServiceMonitor, GxsTransClient { - p3ChatService( p3ServiceControl *cs, p3IdService *pids,p3LinkMgr *cm, - p3HistoryMgr *historyMgr, p3GxsMails& gxsMailService ); + p3ChatService(p3ServiceControl *cs, p3IdService *pids, p3LinkMgr *cm, + p3HistoryMgr *historyMgr, p3GxsTrans& gxsTransService ); virtual RsServiceInfo getServiceInfo(); @@ -171,14 +171,14 @@ struct p3ChatService : uint32_t& error_code, bool notify = true ); - /// @see GxsMailsClient::receiveGxsMail(...) - virtual bool receiveGxsMail( const RsGxsId& authorId, - const RsGxsId& recipientId, - const uint8_t* data, uint32_t dataSize ); + /// @see GxsTransClient::receiveGxsTransMail(...) + virtual bool receiveGxsTransMail( const RsGxsId& authorId, + const RsGxsId& recipientId, + const uint8_t* data, uint32_t dataSize ); - /// @see GxsMailsClient::notifySendMailStatus(...) - virtual bool notifySendMailStatus( const RsGxsMailItem& originalMessage, - GxsMailStatus status ); + /// @see GxsTransClient::notifySendMailStatus(...) + virtual bool notifyGxsTransSendStatus( RsGxsTransId mailId, + GxsTransSendStatus status ); protected: @@ -270,7 +270,7 @@ private: DIDEMap mDistantGxsMap; RsMutex mDGMutex; - p3GxsMails& mGxsTransport; + p3GxsTrans& mGxsTransport; }; class p3ChatService::StateStringInfo diff --git a/libretroshare/src/services/p3gxsmails.cpp b/libretroshare/src/gxstrans/p3gxstrans.cc similarity index 63% rename from libretroshare/src/services/p3gxsmails.cpp rename to libretroshare/src/gxstrans/p3gxstrans.cc index 06acdce96..dab362ce2 100644 --- a/libretroshare/src/services/p3gxsmails.cpp +++ b/libretroshare/src/gxstrans/p3gxstrans.cc @@ -16,39 +16,39 @@ * along with this program. If not, see . */ -#include "p3gxsmails.h" +#include "gxstrans/p3gxstrans.h" #include "util/stacktrace.h" typedef unsigned int uint; -p3GxsMails::~p3GxsMails() +p3GxsTrans::~p3GxsTrans() { p3Config::saveConfiguration(); { - RS_STACK_MUTEX(ingoingMutex); - for ( auto& kv : ingoingQueue ) delete kv.second; + RS_STACK_MUTEX(mIngoingMutex); + for ( auto& kv : mIngoingQueue ) delete kv.second; } } -bool p3GxsMails::sendMail( RsGxsMailId& mailId, - GxsMailSubServices service, +bool p3GxsTrans::sendMail( RsGxsTransId& mailId, + GxsTransSubServices service, const RsGxsId& own_gxsid, const RsGxsId& recipient, const uint8_t* data, uint32_t size, - RsGxsMailEncryptionMode cm ) + RsGxsTransEncryptionMode cm ) { - std::cout << "p3GxsMails::sendEmail(...)" << std::endl; + std::cout << "p3GxsTrans::sendEmail(...)" << std::endl; - if(!idService.isOwnId(own_gxsid)) + if(!mIdService.isOwnId(own_gxsid)) { - std::cerr << "p3GxsMails::sendEmail(...) isOwnId(own_gxsid) false!" + std::cerr << "p3GxsTrans::sendEmail(...) isOwnId(own_gxsid) false!" << std::endl; return false; } if(recipient.isNull()) { - std::cerr << "p3GxsMails::sendEmail(...) got invalid recipient" + std::cerr << "p3GxsTrans::sendEmail(...) got invalid recipient" << std::endl; print_stacktrace(); return false; @@ -60,18 +60,19 @@ bool p3GxsMails::sendMail( RsGxsMailId& mailId, pr.mailItem.mailId = RSRandom::random_u64(); { - RS_STACK_MUTEX(outgoingMutex); - outgoingQueue.insert(prMap::value_type(pr.mailItem.mailId, pr)); + RS_STACK_MUTEX(mOutgoingMutex); + mOutgoingQueue.insert(prMap::value_type(pr.mailItem.mailId, pr)); } mailId = pr.mailItem.mailId; return true; } -bool p3GxsMails::querySendMailStatus(RsGxsMailId mailId, GxsMailStatus& st) +bool p3GxsTrans::querySendStatus(RsGxsTransId mailId, GxsTransSendStatus& st) { - auto it = outgoingQueue.find(mailId); - if( it != outgoingQueue.end() ) + RS_STACK_MUTEX(mOutgoingMutex); + auto it = mOutgoingQueue.find(mailId); + if( it != mOutgoingQueue.end() ) { st = it->second.status; return true; @@ -79,16 +80,16 @@ bool p3GxsMails::querySendMailStatus(RsGxsMailId mailId, GxsMailStatus& st) return false; } -void p3GxsMails::registerGxsMailsClient( - GxsMailSubServices serviceType, GxsMailsClient* service) +void p3GxsTrans::registerGxsTransClient( + GxsTransSubServices serviceType, GxsTransClient* service) { - RS_STACK_MUTEX(servClientsMutex); - servClients[serviceType] = service; + RS_STACK_MUTEX(mServClientsMutex); + mServClients[serviceType] = service; } -void p3GxsMails::handleResponse(uint32_t token, uint32_t req_type) +void p3GxsTrans::handleResponse(uint32_t token, uint32_t req_type) { - std::cout << "p3GxsMails::handleResponse(" << token << ", " << req_type + std::cout << "p3GxsTrans::handleResponse(" << token << ", " << req_type << ")" << std::endl; switch (req_type) { @@ -116,7 +117,7 @@ void p3GxsMails::handleResponse(uint32_t token, uint32_t req_type) bool shoudlSubscribe = !subscribed && ( !old || supersede ); bool shoudlUnSubscribe = subscribed && old - && meta.mGroupId != preferredGroupId; + && meta.mGroupId != mPreferredGroupId; if(shoudlSubscribe) subscribeToGroup(token, meta.mGroupId, true); @@ -129,7 +130,7 @@ void p3GxsMails::handleResponse(uint32_t token, uint32_t req_type) timeinfo = localtime(&meta.mLastPost); strftime(buff, sizeof(buff), "%Y %b %d %H:%M", timeinfo); - std::cout << "p3GxsMails::handleResponse(...) GROUPS_LIST " + std::cout << "p3GxsTrans::handleResponse(...) GROUPS_LIST " << "meta.mGroupId: " << meta.mGroupId << " meta.mLastPost: " << buff << " subscribed: " << subscribed @@ -142,7 +143,7 @@ void p3GxsMails::handleResponse(uint32_t token, uint32_t req_type) delete grp; } - if(preferredGroupId.isNull()) + if(mPreferredGroupId.isNull()) { /* This is true only at first run when we haven't received mail * distribuition groups from friends @@ -150,10 +151,10 @@ void p3GxsMails::handleResponse(uint32_t token, uint32_t req_type) * avoid to create yet another never used mail distribution group. */ - std::cerr << "p3GxsMails::handleResponse(...) preferredGroupId.isNu" + std::cerr << "p3GxsTrans::handleResponse(...) preferredGroupId.isNu" << "ll() let's create a new group." << std::endl; uint32_t token; - publishGroup(token, new RsGxsMailGroupItem()); + publishGroup(token, new RsGxsTransGroupItem()); queueRequest(token, GROUP_CREATE); } @@ -161,7 +162,7 @@ void p3GxsMails::handleResponse(uint32_t token, uint32_t req_type) } case GROUP_CREATE: { - std::cerr << "p3GxsMails::handleResponse(...) GROUP_CREATE" << std::endl; + std::cerr << "p3GxsTrans::handleResponse(...) GROUP_CREATE" << std::endl; RsGxsGroupId grpId; acknowledgeTokenGrp(token, grpId); supersedePreferredGroup(grpId); @@ -169,7 +170,7 @@ void p3GxsMails::handleResponse(uint32_t token, uint32_t req_type) } case MAILS_UPDATE: { - std::cout << "p3GxsMails::handleResponse(...) MAILS_UPDATE" << std::endl; + std::cout << "p3GxsTrans::handleResponse(...) MAILS_UPDATE" << std::endl; typedef std::map > GxsMsgDataMap; GxsMsgDataMap gpMsgMap; getMsgData(token, gpMsgMap); @@ -181,27 +182,27 @@ void p3GxsMails::handleResponse(uint32_t token, uint32_t req_type) for( vT::const_iterator mIt = mv.begin(); mIt != mv.end(); ++mIt ) { RsGxsMsgItem* gIt = *mIt; - switch(static_cast(gIt->PacketSubType())) + switch(static_cast(gIt->PacketSubType())) { - case GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_MAIL: - case GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_RECEIPT: + case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_MAIL: + case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_RECEIPT: { - RsGxsMailBaseItem* mb = - dynamic_cast(*mIt); + RsGxsTransBaseItem* mb = + dynamic_cast(*mIt); if(mb) { - RS_STACK_MUTEX(ingoingMutex); - ingoingQueue.insert(inMap::value_type(mb->mailId, mb)); + RS_STACK_MUTEX(mIngoingMutex); + mIngoingQueue.insert(inMap::value_type(mb->mailId, mb)); } else - std::cerr << "p3GxsMails::handleResponse(...) " + std::cerr << "p3GxsTrans::handleResponse(...) " << "GXS_MAIL_SUBTYPE_MAIL cast error, " << "something really wrong is happening" << std::endl; break; } default: - std::cerr << "p3GxsMails::handleResponse(...) MAILS_UPDATE " + std::cerr << "p3GxsTrans::handleResponse(...) MAILS_UPDATE " << "Unknown mail subtype : " << static_cast(gIt->PacketSubType()) << std::endl; @@ -213,51 +214,51 @@ void p3GxsMails::handleResponse(uint32_t token, uint32_t req_type) break; } default: - std::cerr << "p3GxsMails::handleResponse(...) Unknown req_type: " + std::cerr << "p3GxsTrans::handleResponse(...) Unknown req_type: " << req_type << std::endl; break; } } -void p3GxsMails::service_tick() +void p3GxsTrans::service_tick() { GxsTokenQueue::checkRequests(); { - RS_STACK_MUTEX(outgoingMutex); - for ( auto it = outgoingQueue.begin(); it != outgoingQueue.end(); ) + RS_STACK_MUTEX(mOutgoingMutex); + for ( auto it = mOutgoingQueue.begin(); it != mOutgoingQueue.end(); ) { OutgoingRecord& pr(it->second); - GxsMailStatus oldStatus = pr.status; + GxsTransSendStatus oldStatus = pr.status; processOutgoingRecord(pr); if (oldStatus != pr.status) notifyClientService(pr); - if( pr.status >= GxsMailStatus::RECEIPT_RECEIVED ) - it = outgoingQueue.erase(it); + if( pr.status >= GxsTransSendStatus::RECEIPT_RECEIVED ) + it = mOutgoingQueue.erase(it); else ++it; } } { - RS_STACK_MUTEX(ingoingMutex); - for( auto it = ingoingQueue.begin(); it != ingoingQueue.end(); ) + RS_STACK_MUTEX(mIngoingMutex); + for( auto it = mIngoingQueue.begin(); it != mIngoingQueue.end(); ) { - switch(static_cast( + switch(static_cast( it->second->PacketSubType())) { - case GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_MAIL: + case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_MAIL: { - RsGxsMailItem* msg = dynamic_cast(it->second); + RsGxsTransMailItem* msg = dynamic_cast(it->second); if(!msg) { - std::cerr << "p3GxsMails::service_tick() (EE) " + std::cerr << "p3GxsTrans::service_tick() (EE) " << "GXS_MAIL_SUBTYPE_MAIL dynamic_cast failed, " << "something really wrong is happening!" << std::endl; } else { - std::cout << "p3GxsMails::service_tick() " + std::cout << "p3GxsTrans::service_tick() " << "GXS_MAIL_SUBTYPE_MAIL handling: " << msg->meta.mMsgId << " with cryptoType: " @@ -270,18 +271,18 @@ void p3GxsMails::service_tick() } break; } - case GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_RECEIPT: + case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_RECEIPT: { - RsGxsMailPresignedReceipt* rcpt = - dynamic_cast(it->second); + RsGxsTransPresignedReceipt* rcpt = + dynamic_cast(it->second); if(!rcpt) { - std::cerr << "p3GxsMails::service_tick() (EE) " + std::cerr << "p3GxsTrans::service_tick() (EE) " << "GXS_MAIL_SUBTYPE_RECEIPT dynamic_cast failed," << " something really wrong is happening!" << std::endl; } - else if(idService.isOwnId(rcpt->meta.mAuthorId)) + else if(mIdService.isOwnId(rcpt->meta.mAuthorId)) { /* It is a receipt for a mail sent by this node live it in * ingoingQueue so processOutgoingRecord(...) will take care @@ -298,27 +299,27 @@ void p3GxsMails::service_tick() break; } default: - std::cerr << "p3GxsMails::service_tick() (EE) got something " + std::cerr << "p3GxsTrans::service_tick() (EE) got something " << "really unknown into ingoingQueue!!" << std::endl; break; } - delete it->second; it = ingoingQueue.erase(it); + delete it->second; it = mIngoingQueue.erase(it); } } } -RsGenExchange::ServiceCreate_Return p3GxsMails::service_CreateGroup( +RsGenExchange::ServiceCreate_Return p3GxsTrans::service_CreateGroup( RsGxsGrpItem* grpItem, RsTlvSecurityKeySet& /*keySet*/ ) { - std::cout << "p3GxsMails::service_CreateGroup(...) " + std::cout << "p3GxsTrans::service_CreateGroup(...) " << grpItem->meta.mGroupId << std::endl; return SERVICE_CREATE_SUCCESS; } -void p3GxsMails::notifyChanges(std::vector& changes) +void p3GxsTrans::notifyChanges(std::vector& changes) { - std::cout << "p3GxsMails::notifyChanges(...)" << std::endl; + std::cout << "p3GxsTrans::notifyChanges(...)" << std::endl; for( std::vector::const_iterator it = changes.begin(); it != changes.end(); ++it ) { @@ -327,12 +328,12 @@ void p3GxsMails::notifyChanges(std::vector& changes) if (grpChange) { - std::cout << "p3GxsMails::notifyChanges(...) grpChange" << std::endl; + std::cout << "p3GxsTrans::notifyChanges(...) grpChange" << std::endl; requestGroupsData(&(grpChange->mGrpIdList)); } else if(msgChange) { - std::cout << "p3GxsMails::notifyChanges(...) msgChange" << std::endl; + std::cout << "p3GxsTrans::notifyChanges(...) msgChange" << std::endl; uint32_t token; RsTokReqOptions opts; opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA; getTokenService()->requestMsgInfo( token, 0xcaca, @@ -348,7 +349,7 @@ void p3GxsMails::notifyChanges(std::vector& changes) for(itT vit = msgsIds.begin(); vit != msgsIds.end(); ++vit) { const RsGxsMessageId& msgId = *vit; - std::cout << "p3GxsMails::notifyChanges(...) got " + std::cout << "p3GxsTrans::notifyChanges(...) got " << "notification for message " << msgId << " in group " << grpId << std::endl; } @@ -357,7 +358,7 @@ void p3GxsMails::notifyChanges(std::vector& changes) } } -uint32_t p3GxsMails::AuthenPolicy() +uint32_t p3GxsTrans::AuthenPolicy() { uint32_t policy = 0; uint32_t flag = 0; @@ -386,9 +387,9 @@ uint32_t p3GxsMails::AuthenPolicy() return policy; } -bool p3GxsMails::requestGroupsData(const std::list* groupIds) +bool p3GxsTrans::requestGroupsData(const std::list* groupIds) { - // std::cout << "p3GxsMails::requestGroupsList()" << std::endl; + // std::cout << "p3GxsTrans::requestGroupsList()" << std::endl; uint32_t token; RsTokReqOptions opts; opts.mReqType = GXS_REQUEST_TYPE_GROUP_DATA; if(!groupIds) getTokenService()->requestGroupInfo(token, 0xcaca, opts); @@ -397,26 +398,26 @@ bool p3GxsMails::requestGroupsData(const std::list* groupIds) return true; } -bool p3GxsMails::handleEcryptedMail(const RsGxsMailItem* mail) +bool p3GxsTrans::handleEcryptedMail(const RsGxsTransMailItem* mail) { - std::cout << "p3GxsMails::handleEcryptedMail(...)" << std::endl; + std::cout << "p3GxsTrans::handleEcryptedMail(...)" << std::endl; std::set decryptIds; std::list ownIds; - idService.getOwnIds(ownIds); + mIdService.getOwnIds(ownIds); for(auto it = ownIds.begin(); it != ownIds.end(); ++it) if(mail->maybeRecipient(*it)) decryptIds.insert(*it); // Hint match none of our own ids if(decryptIds.empty()) { - std::cout << "p3GxsMails::handleEcryptedMail(...) hint doesn't match" << std::endl; + std::cout << "p3GxsTrans::handleEcryptedMail(...) hint doesn't match" << std::endl; return true; } switch (mail->cryptoType) { - case RsGxsMailEncryptionMode::CLEAR_TEXT: + case RsGxsTransEncryptionMode::CLEAR_TEXT: { uint16_t csri = 0; uint32_t off = 0; @@ -428,7 +429,7 @@ bool p3GxsMails::handleEcryptedMail(const RsGxsMailItem* mail) return dispatchDecryptedMail( mail->meta.mAuthorId, mail->recipientHint, &mail->payload[0], mail->payload.size() ); } - case RsGxsMailEncryptionMode::RSA: + case RsGxsTransEncryptionMode::RSA: { bool ok = true; for( std::set::const_iterator it = decryptIds.begin(); @@ -438,7 +439,7 @@ bool p3GxsMails::handleEcryptedMail(const RsGxsMailItem* mail) uint8_t* decrypted_data = NULL; uint32_t decrypted_data_size = 0; uint32_t decryption_error; - if( idService.decryptData( &mail->payload[0], + if( mIdService.decryptData( &mail->payload[0], mail->payload.size(), decrypted_data, decrypted_data_size, decryptId, decryption_error ) ) @@ -456,108 +457,108 @@ bool p3GxsMails::handleEcryptedMail(const RsGxsMailItem* mail) } } -bool p3GxsMails::dispatchDecryptedMail( const RsGxsId& authorId, +bool p3GxsTrans::dispatchDecryptedMail( const RsGxsId& authorId, const RsGxsId& decryptId, const uint8_t* decrypted_data, uint32_t decrypted_data_size ) { - std::cout << "p3GxsMails::dispatchDecryptedMail(, , " << decrypted_data_size + std::cout << "p3GxsTrans::dispatchDecryptedMail(, , " << decrypted_data_size << ")" << std::endl; uint16_t csri = 0; uint32_t offset = 0; if(!getRawUInt16( decrypted_data, decrypted_data_size, &offset, &csri)) { - std::cerr << "p3GxsMails::dispatchDecryptedMail(...) (EE) fatal error " + std::cerr << "p3GxsTrans::dispatchDecryptedMail(...) (EE) fatal error " << "deserializing service type, something really wrong is " << "happening!" << std::endl; return false; } - GxsMailSubServices rsrvc = static_cast(csri); + GxsTransSubServices rsrvc = static_cast(csri); - RsNxsMailPresignedReceipt* receipt = new RsNxsMailPresignedReceipt(); + RsNxsTransPresignedReceipt* receipt = new RsNxsTransPresignedReceipt(); uint32_t rcptsize = decrypted_data_size; if(!receipt->deserialize(decrypted_data, rcptsize, offset)) { - std::cerr << "p3GxsMails::dispatchDecryptedMail(...) (EE) fatal error " + std::cerr << "p3GxsTrans::dispatchDecryptedMail(...) (EE) fatal error " << "deserializing presigned return receipt , something really" << " wrong is happening!" << std::endl; delete receipt; return false; } - std::cout << "p3GxsMails::dispatchDecryptedMail(...) dispatching receipt " + std::cout << "p3GxsTrans::dispatchDecryptedMail(...) dispatching receipt " << "with: msgId: " << receipt->msgId << std::endl; std::vector rcct; rcct.push_back(receipt); RsGenExchange::notifyNewMessages(rcct); - GxsMailsClient* recipientService = NULL; + GxsTransClient* recipientService = NULL; { - RS_STACK_MUTEX(servClientsMutex); - recipientService = servClients[rsrvc]; + RS_STACK_MUTEX(mServClientsMutex); + recipientService = mServClients[rsrvc]; } if(recipientService) - return recipientService->receiveGxsMail( authorId, decryptId, - &decrypted_data[offset], - decrypted_data_size-offset ); + return recipientService->receiveGxsTransMail( + authorId, decryptId, &decrypted_data[offset], + decrypted_data_size-offset ); else { - std::cerr << "p3GxsMails::dispatchReceivedMail(...) " + std::cerr << "p3GxsTrans::dispatchReceivedMail(...) " << "got message for unknown service: " << csri << std::endl; return false; } } -void p3GxsMails::processOutgoingRecord(OutgoingRecord& pr) +void p3GxsTrans::processOutgoingRecord(OutgoingRecord& pr) { - //std::cout << "p3GxsMails::processRecord(...)" << std::endl; + //std::cout << "p3GxsTrans::processRecord(...)" << std::endl; switch (pr.status) { - case GxsMailStatus::PENDING_PROCESSING: + case GxsTransSendStatus::PENDING_PROCESSING: { pr.mailItem.saltRecipientHint(pr.recipient); pr.mailItem.saltRecipientHint(RsGxsId::random()); } - case GxsMailStatus::PENDING_PREFERRED_GROUP: + case GxsTransSendStatus::PENDING_PREFERRED_GROUP: { - if(preferredGroupId.isNull()) + if(mPreferredGroupId.isNull()) { requestGroupsData(); - pr.status = GxsMailStatus::PENDING_PREFERRED_GROUP; + pr.status = GxsTransSendStatus::PENDING_PREFERRED_GROUP; break; } - pr.mailItem.meta.mGroupId = preferredGroupId; + pr.mailItem.meta.mGroupId = mPreferredGroupId; } - case GxsMailStatus::PENDING_RECEIPT_CREATE: + case GxsTransSendStatus::PENDING_RECEIPT_CREATE: { - RsGxsMailPresignedReceipt grcpt; + RsGxsTransPresignedReceipt grcpt; grcpt.meta = pr.mailItem.meta; grcpt.meta.mPublishTs = time(NULL); grcpt.mailId = pr.mailItem.mailId; - uint32_t groff = 0, grsz = grcpt.size(); + uint32_t groff = 0, grsz = grcpt.serial_size(); std::vector grsrz; grsrz.resize(grsz); grcpt.serialize(&grsrz[0], grsz, groff); - pr.presignedReceipt.grpId = preferredGroupId; + pr.presignedReceipt.grpId = mPreferredGroupId; pr.presignedReceipt.metaData = new RsGxsMsgMetaData(); *pr.presignedReceipt.metaData = grcpt.meta; pr.presignedReceipt.msg.setBinData(&grsrz[0], grsz); } - case GxsMailStatus::PENDING_RECEIPT_SIGNATURE: + case GxsTransSendStatus::PENDING_RECEIPT_SIGNATURE: { switch (RsGenExchange::createMessage(&pr.presignedReceipt)) { case CREATE_SUCCESS: break; case CREATE_FAIL_TRY_LATER: - pr.status = GxsMailStatus::PENDING_RECEIPT_CREATE; + pr.status = GxsTransSendStatus::PENDING_RECEIPT_CREATE; return; default: - pr.status = GxsMailStatus::FAILED_RECEIPT_SIGNATURE; + pr.status = GxsTransSendStatus::FAILED_RECEIPT_SIGNATURE; goto processingFailed; } @@ -566,7 +567,7 @@ void p3GxsMails::processOutgoingRecord(OutgoingRecord& pr) pr.presignedReceipt.metaData->serialise(&srx[0], &metaSize); pr.presignedReceipt.meta.setBinData(&srx[0], metaSize); } - case GxsMailStatus::PENDING_PAYLOAD_CREATE: + case GxsTransSendStatus::PENDING_PAYLOAD_CREATE: { uint16_t serv = static_cast(pr.clientService); uint32_t rcptsize = pr.presignedReceipt.serial_size(); @@ -579,23 +580,23 @@ void p3GxsMails::processOutgoingRecord(OutgoingRecord& pr) offset += rcptsize; memcpy(&pr.mailItem.payload[offset], &pr.mailData[0], datasize); } - case GxsMailStatus::PENDING_PAYLOAD_ENCRYPT: + case GxsTransSendStatus::PENDING_PAYLOAD_ENCRYPT: { switch (pr.mailItem.cryptoType) { - case RsGxsMailEncryptionMode::CLEAR_TEXT: + case RsGxsTransEncryptionMode::CLEAR_TEXT: { - std::cerr << "p3GxsMails::sendMail(...) you are sending a mail " + std::cerr << "p3GxsTrans::sendMail(...) you are sending a mail " << "without encryption, everyone can read it!" << std::endl; break; } - case RsGxsMailEncryptionMode::RSA: + case RsGxsTransEncryptionMode::RSA: { uint8_t* encryptedData = NULL; uint32_t encryptedSize = 0; uint32_t encryptError = 0; - if( idService.encryptData( &pr.mailItem.payload[0], + if( mIdService.encryptData( &pr.mailItem.payload[0], pr.mailItem.payload.size(), encryptedData, encryptedSize, pr.recipient, encryptError, true ) ) @@ -608,25 +609,25 @@ void p3GxsMails::processOutgoingRecord(OutgoingRecord& pr) } else { - std::cerr << "p3GxsMails::sendMail(...) RSA encryption failed! " + std::cerr << "p3GxsTrans::sendMail(...) RSA encryption failed! " << "error_status: " << encryptError << std::endl; - pr.status = GxsMailStatus::FAILED_ENCRYPTION; + pr.status = GxsTransSendStatus::FAILED_ENCRYPTION; goto processingFailed; } } - case RsGxsMailEncryptionMode::UNDEFINED_ENCRYPTION: + case RsGxsTransEncryptionMode::UNDEFINED_ENCRYPTION: default: - std::cerr << "p3GxsMails::sendMail(...) attempt to send mail with " + std::cerr << "p3GxsTrans::sendMail(...) attempt to send mail with " << "wrong EncryptionMode: " << static_cast(pr.mailItem.cryptoType) << " dropping mail!" << std::endl; - pr.status = GxsMailStatus::FAILED_ENCRYPTION; + pr.status = GxsTransSendStatus::FAILED_ENCRYPTION; goto processingFailed; } } - case GxsMailStatus::PENDING_PUBLISH: + case GxsTransSendStatus::PENDING_PUBLISH: { - std::cout << "p3GxsMails::sendEmail(...) sending mail to: " + std::cout << "p3GxsTrans::sendEmail(...) sending mail to: " << pr.recipient << " with cryptoType: " << static_cast(pr.mailItem.cryptoType) @@ -636,38 +637,38 @@ void p3GxsMails::processOutgoingRecord(OutgoingRecord& pr) << std::endl; uint32_t token; - publishMsg(token, new RsGxsMailItem(pr.mailItem)); - pr.status = GxsMailStatus::PENDING_RECEIPT_RECEIVE; + publishMsg(token, new RsGxsTransMailItem(pr.mailItem)); + pr.status = GxsTransSendStatus::PENDING_RECEIPT_RECEIVE; break; } - //case GxsMailStatus::PENDING_TRANSFER: - case GxsMailStatus::PENDING_RECEIPT_RECEIVE: + //case GxsTransSendStatus::PENDING_TRANSFER: + case GxsTransSendStatus::PENDING_RECEIPT_RECEIVE: { - RS_STACK_MUTEX(ingoingMutex); - auto range = ingoingQueue.equal_range(pr.mailItem.mailId); + RS_STACK_MUTEX(mIngoingMutex); + auto range = mIngoingQueue.equal_range(pr.mailItem.mailId); for( auto it = range.first; it != range.second; ++it) { - RsGxsMailPresignedReceipt* rt = - dynamic_cast(it->second); - if(rt && idService.isOwnId(rt->meta.mAuthorId)) + RsGxsTransPresignedReceipt* rt = + dynamic_cast(it->second); + if(rt && mIdService.isOwnId(rt->meta.mAuthorId)) { - ingoingQueue.erase(it); delete rt; - pr.status = GxsMailStatus::RECEIPT_RECEIVED; + mIngoingQueue.erase(it); delete rt; + pr.status = GxsTransSendStatus::RECEIPT_RECEIVED; break; } } // TODO: Resend message if older then treshold break; } - case GxsMailStatus::RECEIPT_RECEIVED: + case GxsTransSendStatus::RECEIPT_RECEIVED: break; processingFailed: - case GxsMailStatus::FAILED_RECEIPT_SIGNATURE: - case GxsMailStatus::FAILED_ENCRYPTION: + case GxsTransSendStatus::FAILED_RECEIPT_SIGNATURE: + case GxsTransSendStatus::FAILED_ENCRYPTION: default: { - std::cout << "p3GxsMails::processRecord(" << pr.mailItem.mailId + std::cout << "p3GxsTrans::processRecord(" << pr.mailItem.mailId << ") failed with: " << static_cast(pr.status) << std::endl; break; @@ -675,21 +676,21 @@ processingFailed: } } -void p3GxsMails::notifyClientService(const OutgoingRecord& pr) +void p3GxsTrans::notifyClientService(const OutgoingRecord& pr) { - RS_STACK_MUTEX(servClientsMutex); - auto it = servClients.find(pr.clientService); - if( it != servClients.end()) + RS_STACK_MUTEX(mServClientsMutex); + auto it = mServClients.find(pr.clientService); + if( it != mServClients.end()) { - GxsMailsClient* serv(it->second); + GxsTransClient* serv(it->second); if(serv) { - serv->notifySendMailStatus(pr.mailItem, pr.status); + serv->notifyGxsTransSendStatus(pr.mailItem.mailId, pr.status); return; } } - std::cerr << "p3GxsMails::processRecord(...) (EE) processed" + std::cerr << "p3GxsTrans::processRecord(...) (EE) processed" << " mail for unkown service: " << static_cast(pr.clientService) << " fatally failed with: " @@ -697,74 +698,74 @@ void p3GxsMails::notifyClientService(const OutgoingRecord& pr) print_stacktrace(); } -RsSerialiser* p3GxsMails::setupSerialiser() +RsSerialiser* p3GxsTrans::setupSerialiser() { RsSerialiser* rss = new RsSerialiser; - rss->addSerialType(new RsGxsMailSerializer); + rss->addSerialType(new RsGxsTransSerializer); return rss; } -bool p3GxsMails::saveList(bool &cleanup, std::list& saveList) +bool p3GxsTrans::saveList(bool &cleanup, std::list& saveList) { - std::cout << "p3GxsMails::saveList(...)" << saveList.size() << " " - << ingoingQueue.size() << " " << outgoingQueue.size() + std::cout << "p3GxsTrans::saveList(...)" << saveList.size() << " " + << mIngoingQueue.size() << " " << mOutgoingQueue.size() << std::endl; - outgoingMutex.lock(); - ingoingMutex.lock(); + mOutgoingMutex.lock(); + mIngoingMutex.lock(); - for ( auto& kv : outgoingQueue ) saveList.push_back(&kv.second); - for ( auto& kv : ingoingQueue ) saveList.push_back(kv.second); + for ( auto& kv : mOutgoingQueue ) saveList.push_back(&kv.second); + for ( auto& kv : mIngoingQueue ) saveList.push_back(kv.second); - std::cout << "p3GxsMails::saveList(...)" << saveList.size() << " " - << ingoingQueue.size() << " " << outgoingQueue.size() + std::cout << "p3GxsTrans::saveList(...)" << saveList.size() << " " + << mIngoingQueue.size() << " " << mOutgoingQueue.size() << std::endl; cleanup = false; return true; } -void p3GxsMails::saveDone() +void p3GxsTrans::saveDone() { - outgoingMutex.unlock(); - ingoingMutex.unlock(); + mOutgoingMutex.unlock(); + mIngoingMutex.unlock(); } -bool p3GxsMails::loadList(std::list&loadList) +bool p3GxsTrans::loadList(std::list&loadList) { - std::cout << "p3GxsMails::loadList(...) " << loadList.size() << " " - << ingoingQueue.size() << " " << outgoingQueue.size() + std::cout << "p3GxsTrans::loadList(...) " << loadList.size() << " " + << mIngoingQueue.size() << " " << mOutgoingQueue.size() << std::endl; for(auto& v : loadList) - switch(static_cast(v->PacketSubType())) + switch(static_cast(v->PacketSubType())) { - case GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_MAIL: - case GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_RECEIPT: + case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_MAIL: + case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_RECEIPT: { - RsGxsMailBaseItem* mi = dynamic_cast(v); + RsGxsTransBaseItem* mi = dynamic_cast(v); if(mi) { - RS_STACK_MUTEX(ingoingMutex); - ingoingQueue.insert(inMap::value_type(mi->mailId, mi)); + RS_STACK_MUTEX(mIngoingMutex); + mIngoingQueue.insert(inMap::value_type(mi->mailId, mi)); } break; } - case GxsMailItemsSubtypes::OUTGOING_RECORD_ITEM: + case GxsTransItemsSubtypes::OUTGOING_RECORD_ITEM: { OutgoingRecord* ot = dynamic_cast(v); if(ot) { - RS_STACK_MUTEX(outgoingMutex); - outgoingQueue.insert( + RS_STACK_MUTEX(mOutgoingMutex); + mOutgoingQueue.insert( prMap::value_type(ot->mailItem.mailId, *ot)); } delete v; break; } - case GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_GROUP: + case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_GROUP: default: - std::cerr << "p3GxsMails::loadList(...) (EE) got item with " + std::cerr << "p3GxsTrans::loadList(...) (EE) got item with " << "unhandled type: " << static_cast(v->PacketSubType()) << std::endl; @@ -772,8 +773,8 @@ bool p3GxsMails::loadList(std::list&loadList) break; } - std::cout << "p3GxsMails::loadList(...) " << loadList.size() << " " - << ingoingQueue.size() << " " << outgoingQueue.size() + std::cout << "p3GxsTrans::loadList(...) " << loadList.size() << " " + << mIngoingQueue.size() << " " << mOutgoingQueue.size() << std::endl; return true; diff --git a/libretroshare/src/services/p3gxsmails.h b/libretroshare/src/gxstrans/p3gxstrans.h similarity index 59% rename from libretroshare/src/services/p3gxsmails.h rename to libretroshare/src/gxstrans/p3gxstrans.h index 1a9545e66..d03806f72 100644 --- a/libretroshare/src/services/p3gxsmails.h +++ b/libretroshare/src/gxstrans/p3gxstrans.h @@ -23,102 +23,103 @@ #include "retroshare/rsgxsifacetypes.h" // For RsGxsId, RsGxsCircleId #include "gxs/gxstokenqueue.h" // For GxsTokenQueue -#include "serialiser/rsgxsmailitems.h" // For RS_SERVICE_TYPE_GXS_MAIL +#include "gxstrans/p3gxstransitems.h" #include "services/p3idservice.h" // For p3IdService #include "util/rsthreads.h" -struct p3GxsMails; +struct p3GxsTrans; -/// Services who want to make use of p3GxsMails should inherit this struct -struct GxsMailsClient +/// Services who want to make use of p3GxsTrans should inherit this struct +struct GxsTransClient { /** - * This will be called by p3GxsMails to dispatch mails to the subservice + * This will be called by p3GxsTrans to dispatch mails to the subservice * @param authorId message sender * @param decryptId recipient id * @param data buffer containing the decrypted data * @param dataSize size of the buffer * @return true if dispatching goes fine, false otherwise */ - virtual bool receiveGxsMail( const RsGxsId& authorId, - const RsGxsId& recipientId, - const uint8_t* data, uint32_t dataSize ) = 0; + virtual bool receiveGxsTransMail( const RsGxsId& authorId, + const RsGxsId& recipientId, + const uint8_t* data, uint32_t dataSize + ) = 0; /** - * This will be called by p3GxsMails to notify the subservice about the + * This will be called by p3GxsTrans to notify the subservice about the * status of a sent email. * @param originalMessage message for with the notification is made * @param status the new status of the message * @return true if notification goes fine, false otherwise (ignored ATM) */ - virtual bool notifySendMailStatus( const RsGxsMailItem& originalMessage, - GxsMailStatus status ) = 0; + virtual bool notifyGxsTransSendStatus( RsGxsTransId mailId, + GxsTransSendStatus status ) = 0; }; /** - * @brief p3GxsMails is a mail delivery service based on GXS. - * p3GxsMails is capable of asynchronous mail delivery and acknowledgement. - * p3GxsMails is meant to be capable of multiple encryption options, - * @see RsGxsMailEncryptionMode at moment messages are encrypted using RSA + * @brief p3GxsTrans is a mail delivery service based on GXS. + * p3GxsTrans is capable of asynchronous mail delivery and acknowledgement. + * p3GxsTrans is meant to be capable of multiple encryption options, + * @see RsGxsTransEncryptionMode at moment messages are encrypted using RSA * unless the user ask for them being sent in clear text ( this is not supposed * to happen in non testing environment so warnings and stack traces are printed * in the log if an attempt to send something in clear text is made ). - * p3GxsMails try to hide metadata so the travelling message signed by the author + * p3GxsTrans try to hide metadata so the travelling message signed by the author * but the recipient is not disclosed, instead to avoid everyone trying to * decrypt every message a hint has been introduced, the hint is calculated in a * way that one can easily prove that a message is not destined to someone, but * cannot prove the message is destined to someone - * @see RsGxsMailItem::recipientsHint for more details. - * p3GxsMails expose a simple API to send and receive mails, the API also + * @see RsGxsTransMailItem::recipientHint for more details. + * p3GxsTrans expose a simple API to send and receive mails, the API also * provide notification for the sending mail status @see sendMail(...), - * @see querySendMailStatus(...), @see registerGxsMailsClient(...), - * @see GxsMailsClient::receiveGxsMail(...), - * @see GxsMailsClient::notifySendMailStatus(...). + * @see querySendStatus(...), @see registerGxsTransClient(...), + * @see GxsTransClient::receiveGxsTransMail(...), + * @see GxsTransClient::notifyGxsTransSendStatus(...). */ -struct p3GxsMails : RsGenExchange, GxsTokenQueue, p3Config +struct p3GxsTrans : RsGenExchange, GxsTokenQueue, p3Config { - p3GxsMails( RsGeneralDataService* gds, RsNetworkExchangeService* nes, + p3GxsTrans( RsGeneralDataService* gds, RsNetworkExchangeService* nes, p3IdService& identities ) : - RsGenExchange( gds, nes, new RsGxsMailSerializer(), - RS_SERVICE_TYPE_GXS_MAIL, &identities, + RsGenExchange( gds, nes, new RsGxsTransSerializer(), + RS_SERVICE_TYPE_GXS_TRANS, &identities, AuthenPolicy(), GXS_STORAGE_PERIOD ), - GxsTokenQueue(this), idService(identities), - servClientsMutex("p3GxsMails client services map mutex"), - outgoingMutex("p3GxsMails outgoing queue map mutex"), - ingoingMutex("p3GxsMails ingoing queue map mutex") {} - ~p3GxsMails(); + GxsTokenQueue(this), mIdService(identities), + mServClientsMutex("p3GxsTrans client services map mutex"), + mOutgoingMutex("p3GxsTrans outgoing queue map mutex"), + mIngoingMutex("p3GxsTrans ingoing queue map mutex") {} + ~p3GxsTrans(); /** * Send an email to recipient, in the process author of the email is * disclosed to the network (because the sent GXS item is signed), while - * recipient is not @see RsGxsMailBaseItem::recipientsHint for details on + * recipient is not @see RsGxsTransMailItem::recipientHint for details on * recipient protection. * This method is part of the public interface of this service. * @return true if the mail will be sent, false if not */ - bool sendMail( RsGxsMailId& mailId, - GxsMailSubServices service, + bool sendMail( RsGxsTransId& mailId, + GxsTransSubServices service, const RsGxsId& own_gxsid, const RsGxsId& recipient, const uint8_t* data, uint32_t size, - RsGxsMailEncryptionMode cm = RsGxsMailEncryptionMode::RSA + RsGxsTransEncryptionMode cm = RsGxsTransEncryptionMode::RSA ); /** * This method is part of the public interface of this service. * @return false if mail is not found in outgoing queue, true otherwise */ - bool querySendMailStatus( RsGxsMailId mailId, GxsMailStatus& st ); + bool querySendStatus( RsGxsTransId mailId, GxsTransSendStatus& st ); /** - * Register a client service to p3GxsMails to receive mails via - * GxsMailsClient::receiveGxsMail(...) callback + * Register a client service to p3GxsTrans to receive mails via + * GxsTransClient::receiveGxsTransMail(...) callback * This method is part of the public interface of this service. */ - void registerGxsMailsClient( GxsMailSubServices serviceType, - GxsMailsClient* service ); + void registerGxsTransClient( GxsTransSubServices serviceType, + GxsTransClient* service ); /// @see RsGenExchange::getServiceInfo() - virtual RsServiceInfo getServiceInfo() { return RsServiceInfo( RS_SERVICE_TYPE_GXS_MAIL, "GXS Mails", 0, 1, 0, 1 ); } + virtual RsServiceInfo getServiceInfo() { return RsServiceInfo( RS_SERVICE_TYPE_GXS_TRANS, "GXS Mails", 0, 1, 0, 1 ); } private: /** Time interval of inactivity before a distribution group is unsubscribed. @@ -152,14 +153,14 @@ private: }; /// Store the id of the preferred GXS group to send emails - RsGxsGroupId preferredGroupId; + RsGxsGroupId mPreferredGroupId; /// Used for items {de,en}cryption - p3IdService& idService; + p3IdService& mIdService; /// Stores pointers to client services to notify them about new mails - std::map servClients; - RsMutex servClientsMutex; + std::map mServClients; + RsMutex mServClientsMutex; /** * @brief Keep track of outgoing mails. @@ -167,9 +168,9 @@ private: * receipt has been received or sending is considered definetly failed. * Items are saved in config for consistence accross RetroShare shutdowns. */ - typedef std::map prMap; - prMap outgoingQueue; - RsMutex outgoingMutex; + typedef std::map prMap; + prMap mOutgoingQueue; + RsMutex mOutgoingMutex; void processOutgoingRecord(OutgoingRecord& r); /** @@ -181,9 +182,9 @@ private: * item to not being processed and memleaked multimap is used instead of map * for incoming queue. */ - typedef std::unordered_multimap inMap; - inMap ingoingQueue; - RsMutex ingoingMutex; + typedef std::unordered_multimap inMap; + inMap mIngoingQueue; + RsMutex mIngoingMutex; /// @see GxsTokenQueue::handleResponse(uint32_t token, uint32_t req_type) virtual void handleResponse(uint32_t token, uint32_t req_type); @@ -223,11 +224,11 @@ private: */ bool inline supersedePreferredGroup(const RsGxsGroupId& potentialGrId) { - if(preferredGroupId < potentialGrId) + if(mPreferredGroupId < potentialGrId) { std::cerr << "supersedePreferredGroup(...) " << potentialGrId - << " supersed " << preferredGroupId << std::endl; - preferredGroupId = potentialGrId; + << " supersed " << mPreferredGroupId << std::endl; + mPreferredGroupId = potentialGrId; return true; } return false; @@ -241,7 +242,7 @@ private: /// Decrypt email content and pass it to dispatchDecryptedMail(...) - bool handleEcryptedMail(const RsGxsMailItem* mail); + bool handleEcryptedMail(const RsGxsTransMailItem* mail); /// Dispatch the message to the recipient service bool dispatchDecryptedMail( const RsGxsId& authorId, @@ -252,72 +253,3 @@ private: void notifyClientService(const OutgoingRecord& pr); }; -#ifdef TEST_RS_GXS_MAIL - -struct TestGxsMailClientService : GxsMailsClient, RsSingleJobThread -{ - TestGxsMailClientService( p3GxsMails& gxsMailService, - p3IdService& gxsIdService ) : - mailService(gxsMailService), idService(gxsIdService) - { - mailService.registerGxsMailsClient( GxsMailSubServices::TEST_SERVICE, - this ); - } - - /// @see GxsMailsClient::receiveGxsMail(...) - virtual bool receiveGxsMail( const RsGxsMailItem& originalMessage, - const uint8_t* data, uint32_t dataSize ) - { - std::cout << "TestGxsMailClientService::receiveGxsMail(...) got message" - << " from: " << originalMessage.meta.mAuthorId << std::endl - << "\t>" << std::string((char*)data, dataSize) << "<" - << std::endl; - return true; - } - - /// @see GxsMailsClient::notifyMailStatus(...) - virtual bool notifySendMailStatus( const RsGxsMailItem& originalMessage, - GxsMailStatus status ) - { - std::cout << "TestGxsMailClientService::notifyMailsStatus(...) for: " - << originalMessage.mailId << " status: " - << static_cast(status) << std::endl; - if( status == GxsMailStatus::RECEIPT_RECEIVED ) - std::cout << "\t It mean Receipt has been Received!" << std::endl; - return true; - } - - /// @see RsSingleJobThread::run() - virtual void run() - { -#if 0 - usleep(10*1000*1000); - RsGxsId gxsidA("d0df7474bdde0464679e6ef787890287"); - RsGxsId gxsidB("d060bea09dfa14883b5e6e517eb580cd"); - RsGxsMailId mailId = 0; - if(idService.isOwnId(gxsidA)) - { - std::string ciao("CiAone!"); - mailService.sendMail( mailId, GxsMailSubServices::TEST_SERVICE, - gxsidA, gxsidB, - reinterpret_cast(ciao.data()), - ciao.size() ); - } - else if(idService.isOwnId(gxsidB)) - { - std::string ciao("CiBuono!"); - mailService.sendMail( mailId, GxsMailSubServices::TEST_SERVICE, - gxsidB, gxsidA, - reinterpret_cast(ciao.data()), - ciao.size() ); - } -#endif - } - -private: - p3GxsMails& mailService; - p3IdService& idService; -}; - -#endif // TEST_RS_GXS_MAIL - diff --git a/libretroshare/src/serialiser/rsgxsmailitems.cc b/libretroshare/src/gxstrans/p3gxstransitems.cc similarity index 71% rename from libretroshare/src/serialiser/rsgxsmailitems.cc rename to libretroshare/src/gxstrans/p3gxstransitems.cc index 6aca99b37..886760215 100644 --- a/libretroshare/src/serialiser/rsgxsmailitems.cc +++ b/libretroshare/src/gxstrans/p3gxstransitems.cc @@ -16,12 +16,12 @@ * along with this program. If not, see . */ -#include "serialiser/rsgxsmailitems.h" +#include "gxstrans/p3gxstransitems.h" -const RsGxsId RsGxsMailItem::allRecipientsHint("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); +const RsGxsId RsGxsTransMailItem::allRecipientsHint("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); -bool RsGxsMailBaseItem::serialize(uint8_t* data, uint32_t size, +bool RsGxsTransBaseItem::serialize(uint8_t* data, uint32_t size, uint32_t& offset) const { bool ok = setRsItemHeader(data+offset, size, PacketId(), size); @@ -30,8 +30,8 @@ bool RsGxsMailBaseItem::serialize(uint8_t* data, uint32_t size, return ok; } -bool RsGxsMailBaseItem::deserialize(const uint8_t* data, uint32_t& size, - uint32_t& offset) +bool RsGxsTransBaseItem::deserialize( const uint8_t* data, uint32_t& size, + uint32_t& offset) { void* hdrPtr = const_cast(data+offset); uint32_t rssize = getRsItemSize(hdrPtr); @@ -45,42 +45,42 @@ bool RsGxsMailBaseItem::deserialize(const uint8_t* data, uint32_t& size, return ok; } -std::ostream& RsGxsMailBaseItem::print(std::ostream &out, uint16_t) -{ return out << " RsGxsMailBaseItem::mailId: " << mailId; } +std::ostream& RsGxsTransBaseItem::print(std::ostream &out, uint16_t) +{ return out << __PRETTY_FUNCTION__ << " mailId: " << mailId; } -bool RsGxsMailSerializer::serialise(RsItem* item, void* data, uint32_t* size) +bool RsGxsTransSerializer::serialise(RsItem* item, void* data, uint32_t* size) { - uint32_t itemSize = RsGxsMailSerializer::size(item); + uint32_t itemSize = RsGxsTransSerializer::size(item); if(*size < itemSize) { - std::cout << "RsGxsMailSerializer::serialise(...) failed due to wrong size: " + std::cout << __PRETTY_FUNCTION__ << " failed due to wrong size: " << size << " < " << itemSize << std::endl; return false; } uint8_t* dataPtr = reinterpret_cast(data); bool ok = false; - switch(static_cast(item->PacketSubType())) + switch(static_cast(item->PacketSubType())) { - case GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_MAIL: + case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_MAIL: { uint32_t offset = 0; - RsGxsMailItem* i = dynamic_cast(item); + RsGxsTransMailItem* i = dynamic_cast(item); ok = i && i->serialize(dataPtr, itemSize, offset); break; } - case GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_RECEIPT: + case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_RECEIPT: { - RsGxsMailPresignedReceipt* i = - dynamic_cast(item); + RsGxsTransPresignedReceipt* i = + dynamic_cast(item); uint32_t offset = 0; ok = i && i->serialize(dataPtr, itemSize, offset); break; } - case GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_GROUP: + case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_GROUP: ok = setRsItemHeader(data, itemSize, item->PacketId(), itemSize); break; - case GxsMailItemsSubtypes::OUTGOING_RECORD_ITEM: + case GxsTransItemsSubtypes::OUTGOING_RECORD_ITEM: { uint32_t offset = 0; OutgoingRecord* i = dynamic_cast(item); @@ -96,15 +96,15 @@ bool RsGxsMailSerializer::serialise(RsItem* item, void* data, uint32_t* size) return true; } - std::cout << "RsGxsMailSerializer::serialise(...) failed!" << std::endl; + std::cout << __PRETTY_FUNCTION__ << " failed!" << std::endl; return false; } -OutgoingRecord::OutgoingRecord( RsGxsId rec, GxsMailSubServices cs, +OutgoingRecord::OutgoingRecord( RsGxsId rec, GxsTransSubServices cs, const uint8_t* data, uint32_t size ) : - RsItem( RS_PKT_VERSION_SERVICE, RS_SERVICE_TYPE_GXS_MAIL, - static_cast(GxsMailItemsSubtypes::OUTGOING_RECORD_ITEM) ), - status(GxsMailStatus::PENDING_PROCESSING), recipient(rec), + RsItem( RS_PKT_VERSION_SERVICE, RS_SERVICE_TYPE_GXS_TRANS, + static_cast(GxsTransItemsSubtypes::OUTGOING_RECORD_ITEM) ), + status(GxsTransSendStatus::PENDING_PROCESSING), recipient(rec), clientService(cs) { mailData.resize(size); @@ -113,11 +113,11 @@ OutgoingRecord::OutgoingRecord( RsGxsId rec, GxsMailSubServices cs, void OutgoingRecord::clear() { - status = GxsMailStatus::UNKNOWN; + status = GxsTransSendStatus::UNKNOWN; recipient.clear(); mailItem.clear(); mailData.clear(); - clientService = GxsMailSubServices::UNKNOWN; + clientService = GxsTransSubServices::UNKNOWN; presignedReceipt.clear(); } @@ -125,8 +125,8 @@ std::ostream& OutgoingRecord::print(std::ostream& out, uint16_t) { return out << "TODO: OutgoingRecordItem::print(...)"; } OutgoingRecord::OutgoingRecord() : - RsItem( RS_PKT_VERSION_SERVICE, RS_SERVICE_TYPE_GXS_MAIL, - static_cast(GxsMailItemsSubtypes::OUTGOING_RECORD_ITEM) ) + RsItem( RS_PKT_VERSION_SERVICE, RS_SERVICE_TYPE_GXS_TRANS, + static_cast(GxsTransItemsSubtypes::OUTGOING_RECORD_ITEM) ) { clear();} uint32_t OutgoingRecord::size() const @@ -134,7 +134,7 @@ uint32_t OutgoingRecord::size() const return 8 + // Header 1 + // status recipient.serial_size() + - mailItem.size() + + mailItem.serial_size() + 4 + // sizeof(mailData.size()) mailData.size() + 2 + // clientService @@ -154,7 +154,7 @@ bool OutgoingRecord::serialize( uint8_t* data, uint32_t size, ok = ok && recipient.serialise(data, size, offset); uint32_t tmpOffset = 0; - uint32_t tmpSize = mailItem.size(); + uint32_t tmpSize = mailItem.serial_size(); ok = ok && mailItem.serialize(data+offset, tmpSize, tmpOffset) && (offset += tmpOffset); @@ -182,7 +182,7 @@ bool OutgoingRecord::deserialize( uint8_t tmpStatus = 0; ok = ok && getRawUInt8(dataPtr, size, &offset, &tmpStatus); - status = static_cast(tmpStatus); + status = static_cast(tmpStatus); uint32_t tmpSize = size; ok = ok && recipient.deserialise(dataPtr, tmpSize, offset); @@ -202,7 +202,7 @@ bool OutgoingRecord::deserialize( uint16_t cs = 0; ok = ok && getRawUInt16(dataPtr, offset+2, &offset, &cs); - clientService = static_cast(cs); + clientService = static_cast(cs); tmpSize = size; ok = ok && presignedReceipt.deserialize(data, tmpSize, offset); diff --git a/libretroshare/src/serialiser/rsgxsmailitems.h b/libretroshare/src/gxstrans/p3gxstransitems.h similarity index 71% rename from libretroshare/src/serialiser/rsgxsmailitems.h rename to libretroshare/src/gxstrans/p3gxstransitems.h index ac255b3f5..3f3d38145 100644 --- a/libretroshare/src/serialiser/rsgxsmailitems.h +++ b/libretroshare/src/gxstrans/p3gxstransitems.h @@ -19,7 +19,7 @@ #include -#include "rsgxsitems.h" +#include "serialiser/rsgxsitems.h" #include "serialiser/rsbaseserial.h" #include "serialiser/rstlvidset.h" #include "retroshare/rsgxsflags.h" @@ -27,7 +27,7 @@ #include "services/p3idservice.h" /// Subservices identifiers (like port for TCP) -enum class GxsMailSubServices : uint16_t +enum class GxsTransSubServices : uint16_t { UNKNOWN = 0, TEST_SERVICE = 1, @@ -36,28 +36,28 @@ enum class GxsMailSubServices : uint16_t }; /// Values must fit into uint8_t -enum class GxsMailItemsSubtypes : uint8_t +enum class GxsTransItemsSubtypes : uint8_t { - GXS_MAIL_SUBTYPE_MAIL = 1, - GXS_MAIL_SUBTYPE_RECEIPT = 2, - GXS_MAIL_SUBTYPE_GROUP = 3, - OUTGOING_RECORD_ITEM = 4 + GXS_TRANS_SUBTYPE_MAIL = 1, + GXS_TRANS_SUBTYPE_RECEIPT = 2, + GXS_TRANS_SUBTYPE_GROUP = 3, + OUTGOING_RECORD_ITEM = 4 }; -typedef uint64_t RsGxsMailId; +typedef uint64_t RsGxsTransId; -struct RsNxsMailPresignedReceipt : RsNxsMsg +struct RsNxsTransPresignedReceipt : RsNxsMsg { - RsNxsMailPresignedReceipt() : RsNxsMsg(RS_SERVICE_TYPE_GXS_MAIL) {} + RsNxsTransPresignedReceipt() : RsNxsMsg(RS_SERVICE_TYPE_GXS_TRANS) {} }; -struct RsGxsMailBaseItem : RsGxsMsgItem +struct RsGxsTransBaseItem : RsGxsMsgItem { - RsGxsMailBaseItem(GxsMailItemsSubtypes subtype) : - RsGxsMsgItem( RS_SERVICE_TYPE_GXS_MAIL, + RsGxsTransBaseItem(GxsTransItemsSubtypes subtype) : + RsGxsMsgItem( RS_SERVICE_TYPE_GXS_TRANS, static_cast(subtype) ), mailId(0) {} - RsGxsMailId mailId; + RsGxsTransId mailId; void inline clear() { @@ -65,7 +65,7 @@ struct RsGxsMailBaseItem : RsGxsMsgItem meta = RsMsgMetaData(); } - static uint32_t inline size() + static uint32_t inline serial_size() { return 8 + // Header 8; // mailId @@ -75,29 +75,29 @@ struct RsGxsMailBaseItem : RsGxsMsgItem std::ostream &print(std::ostream &out, uint16_t /*indent = 0*/); }; -struct RsGxsMailPresignedReceipt : RsGxsMailBaseItem +struct RsGxsTransPresignedReceipt : RsGxsTransBaseItem { - RsGxsMailPresignedReceipt() : - RsGxsMailBaseItem(GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_RECEIPT) {} + RsGxsTransPresignedReceipt() : + RsGxsTransBaseItem(GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_RECEIPT) {} }; -enum class RsGxsMailEncryptionMode : uint8_t +enum class RsGxsTransEncryptionMode : uint8_t { CLEAR_TEXT = 1, RSA = 2, UNDEFINED_ENCRYPTION = 250 }; -struct RsGxsMailItem : RsGxsMailBaseItem +struct RsGxsTransMailItem : RsGxsTransBaseItem { - RsGxsMailItem() : - RsGxsMailBaseItem(GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_MAIL), - cryptoType(RsGxsMailEncryptionMode::UNDEFINED_ENCRYPTION) {} + RsGxsTransMailItem() : + RsGxsTransBaseItem(GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_MAIL), + cryptoType(RsGxsTransEncryptionMode::UNDEFINED_ENCRYPTION) {} - RsGxsMailEncryptionMode cryptoType; + RsGxsTransEncryptionMode cryptoType; /** - * @brief recipientsHint used instead of plain recipient id, so sender can + * @brief recipientHint used instead of plain recipient id, so sender can * decide the equilibrium between exposing the recipient and the cost of * completely anonymize it. So a bunch of luky non recipient can conclude * rapidly that they are not the recipient without trying to decrypt the @@ -112,7 +112,7 @@ struct RsGxsMailItem : RsGxsMailBaseItem * keys and an arbitrary salt, the more recipients has the mail and the more * 1 bits has the salt the less accurate is the hint. * This way the sender is able to adjust the metadata privacy needed for the - * message, in the more private case (recipientsHint == 0xFFF...FFF) no one + * message, in the more private case (recipientHint == 0xFFF...FFF) no one * has a clue about who is the actual recipient, while this imply the cost * that every potencial recipient has to try to decrypt it to know if it is * for herself. This way a bunch of non recipients can rapidly discover that @@ -149,9 +149,9 @@ struct RsGxsMailItem : RsGxsMailBaseItem * is specified */ std::vector payload; - uint32_t size() const + uint32_t serial_size() const { - return RsGxsMailBaseItem::size() + + return RsGxsTransBaseItem::serial_size() + 1 + // cryptoType recipientHint.serial_size() + payload.size(); @@ -159,7 +159,7 @@ struct RsGxsMailItem : RsGxsMailBaseItem bool serialize(uint8_t* data, uint32_t size, uint32_t& offset) const { bool ok = size < MAX_SIZE; - ok = ok && RsGxsMailBaseItem::serialize(data, size, offset); + ok = ok && RsGxsTransBaseItem::serialize(data, size, offset); ok = ok && setRawUInt8( data, size, &offset, static_cast(cryptoType) ); ok = ok && recipientHint.serialise(data, size, offset); @@ -175,12 +175,12 @@ struct RsGxsMailItem : RsGxsMailBaseItem uint32_t roffset = offset; bool ok = rssize <= size && size < MAX_SIZE; - ok = ok && RsGxsMailBaseItem::deserialize(data, rssize, roffset); + ok = ok && RsGxsTransBaseItem::deserialize(data, rssize, roffset); void* dataPtr = const_cast(data); uint8_t crType; ok = ok && getRawUInt8(dataPtr, rssize, &roffset, &crType); - cryptoType = static_cast(crType); + cryptoType = static_cast(crType); ok = ok && recipientHint.deserialise(dataPtr, rssize, roffset); uint32_t psz = rssize - roffset; ok = ok && (payload.resize(psz), memcpy(&payload[0], data+roffset, psz)); @@ -191,8 +191,8 @@ struct RsGxsMailItem : RsGxsMailBaseItem } void clear() { - RsGxsMailBaseItem::clear(); - cryptoType = RsGxsMailEncryptionMode::UNDEFINED_ENCRYPTION; + RsGxsTransBaseItem::clear(); + cryptoType = RsGxsTransEncryptionMode::UNDEFINED_ENCRYPTION; recipientHint.clear(); payload.clear(); } @@ -201,12 +201,12 @@ struct RsGxsMailItem : RsGxsMailBaseItem const static uint32_t MAX_SIZE = 10*8*1024*1024; }; -struct RsGxsMailGroupItem : RsGxsGrpItem +struct RsGxsTransGroupItem : RsGxsGrpItem { - RsGxsMailGroupItem() : - RsGxsGrpItem( RS_SERVICE_TYPE_GXS_MAIL, + RsGxsTransGroupItem() : + RsGxsGrpItem( RS_SERVICE_TYPE_GXS_TRANS, static_cast( - GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_GROUP) ) + GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_GROUP) ) { meta.mGroupFlags = GXS_SERV::FLAG_PRIVACY_PUBLIC; meta.mGroupName = "Mail"; @@ -218,7 +218,7 @@ struct RsGxsMailGroupItem : RsGxsGrpItem { return out; } }; -enum class GxsMailStatus : uint8_t +enum class GxsTransSendStatus : uint8_t { UNKNOWN = 0, PENDING_PROCESSING, @@ -239,19 +239,19 @@ enum class GxsMailStatus : uint8_t FAILED_ENCRYPTION }; -class RsGxsMailSerializer; +class RsGxsTransSerializer; struct OutgoingRecord : RsItem { - OutgoingRecord( RsGxsId rec, GxsMailSubServices cs, + OutgoingRecord( RsGxsId rec, GxsTransSubServices cs, const uint8_t* data, uint32_t size ); - GxsMailStatus status; + GxsTransSendStatus status; RsGxsId recipient; /// Don't use a pointer would be invalid after publish - RsGxsMailItem mailItem; + RsGxsTransMailItem mailItem; std::vector mailData; - GxsMailSubServices clientService; - RsNxsMailPresignedReceipt presignedReceipt; + GxsTransSubServices clientService; + RsNxsTransPresignedReceipt presignedReceipt; uint32_t size() const; bool serialize(uint8_t* data, uint32_t size, uint32_t& offset) const; @@ -261,32 +261,32 @@ struct OutgoingRecord : RsItem virtual std::ostream &print(std::ostream &out, uint16_t indent = 0); private: - friend class RsGxsMailSerializer; + friend class RsGxsTransSerializer; OutgoingRecord(); }; -struct RsGxsMailSerializer : RsSerialType +struct RsGxsTransSerializer : RsSerialType { - RsGxsMailSerializer() : RsSerialType( RS_PKT_VERSION_SERVICE, - RS_SERVICE_TYPE_GXS_MAIL ) {} - ~RsGxsMailSerializer() {} + RsGxsTransSerializer() : RsSerialType( RS_PKT_VERSION_SERVICE, + RS_SERVICE_TYPE_GXS_TRANS ) {} + ~RsGxsTransSerializer() {} uint32_t size(RsItem* item) { uint32_t sz = 0; - switch(static_cast(item->PacketSubType())) + switch(static_cast(item->PacketSubType())) { - case GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_MAIL: + case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_MAIL: { - RsGxsMailItem* i = dynamic_cast(item); - if(i) sz = i->size(); + RsGxsTransMailItem* i = dynamic_cast(item); + if(i) sz = i->serial_size(); break; } - case GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_RECEIPT: - sz = RsGxsMailPresignedReceipt::size(); break; - case GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_GROUP: sz = 8; break; - case GxsMailItemsSubtypes::OUTGOING_RECORD_ITEM: + case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_RECEIPT: + sz = RsGxsTransPresignedReceipt::serial_size(); break; + case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_GROUP: sz = 8; break; + case GxsTransItemsSubtypes::OUTGOING_RECORD_ITEM: { OutgoingRecord* ci = dynamic_cast(item); if(ci) sz = ci->size(); @@ -309,7 +309,7 @@ struct RsGxsMailSerializer : RsSerialType const uint8_t* dataPtr = reinterpret_cast(data); if ( (RS_PKT_VERSION_SERVICE != pktv) || // 0x02 - (RS_SERVICE_TYPE_GXS_MAIL != srvc) || // 0x0230 = 560 + (RS_SERVICE_TYPE_GXS_TRANS != srvc) || // 0x0230 = 560 (*size < rssize) ) { print_stacktrace(); @@ -320,30 +320,30 @@ struct RsGxsMailSerializer : RsSerialType bool ok = true; RsItem* ret = NULL; - switch (static_cast(getRsItemSubType(rstype))) + switch (static_cast(getRsItemSubType(rstype))) { - case GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_MAIL: + case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_MAIL: { - RsGxsMailItem* i = new RsGxsMailItem(); + RsGxsTransMailItem* i = new RsGxsTransMailItem(); uint32_t offset = 0; ok = ok && i->deserialize(dataPtr, *size, offset); ret = i; break; } - case GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_RECEIPT: + case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_RECEIPT: { - RsGxsMailPresignedReceipt* i = new RsGxsMailPresignedReceipt(); + RsGxsTransPresignedReceipt* i = new RsGxsTransPresignedReceipt(); uint32_t offset = 0; ok &= i->deserialize(dataPtr, *size, offset); ret = i; break; } - case GxsMailItemsSubtypes::GXS_MAIL_SUBTYPE_GROUP: + case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_GROUP: { - ret = new RsGxsMailGroupItem(); + ret = new RsGxsTransGroupItem(); break; } - case GxsMailItemsSubtypes::OUTGOING_RECORD_ITEM: + case GxsTransItemsSubtypes::OUTGOING_RECORD_ITEM: { OutgoingRecord* i = new OutgoingRecord(); uint32_t offset = 0; diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index dbbe6414b..85fbdc9f7 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -852,9 +852,9 @@ gxsphotoshare { serialiser/rsphotoitems.cc \ } -rs_gxs_mail { - HEADERS += serialiser/rsgxsmailitems.h services/p3gxsmails.h - SOURCES += serialiser/rsgxsmailitems.cc services/p3gxsmails.cpp +rs_gxs_trans { + HEADERS += gxstrans/p3gxstransitems.h gxstrans/p3gxstrans.h + SOURCES += gxstrans/p3gxstransitems.cc gxstrans/p3gxstrans.cc } diff --git a/libretroshare/src/rsserver/p3face-server.cc b/libretroshare/src/rsserver/p3face-server.cc index 28b223341..a7aad022c 100644 --- a/libretroshare/src/rsserver/p3face-server.cc +++ b/libretroshare/src/rsserver/p3face-server.cc @@ -122,7 +122,7 @@ RsServer::RsServer() RsServer::~RsServer() { - delete mGxsMails; + delete mGxsTrans; } /* General Internal Helper Functions diff --git a/libretroshare/src/rsserver/p3face.h b/libretroshare/src/rsserver/p3face.h index de30f908d..e8a1ba66f 100644 --- a/libretroshare/src/rsserver/p3face.h +++ b/libretroshare/src/rsserver/p3face.h @@ -179,7 +179,7 @@ class RsServer: public RsControl, public RsTickingThread // p3GxsForums *mGxsForums; // p3GxsChannels *mGxsChannels; // p3Wire *mWire; - p3GxsMails* mGxsMails; + p3GxsTrans* mGxsTrans; /* Config */ p3ConfigMgr *mConfigMgr; diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index 2b6c8f9d9..42dca1c42 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -82,8 +82,8 @@ #include "tcponudp/udpstunner.h" #endif // RS_USE_DHT_STUNNER -#ifdef RS_GXS_MAIL -# include "services/p3gxsmails.h" +#ifdef RS_GXS_TRANS +# include "gxstrans/p3gxstrans.h" #endif // #define GPG_DEBUG @@ -1484,22 +1484,18 @@ int RsServer::StartupRetroShare() pqih->addService(gxschannels_ns, true); //pqih->addService(photo_ns, true); -# ifdef RS_GXS_MAIL - RsGeneralDataService* gxsmail_ds = new RsDataService( - currGxsDir + "/", "gxsmails_db", RS_SERVICE_TYPE_GXS_MAIL, +# ifdef RS_GXS_TRANS + RsGeneralDataService* gxstrans_ds = new RsDataService( + currGxsDir + "/", "gxstrans_db", RS_SERVICE_TYPE_GXS_TRANS, NULL, rsInitConfig->gxs_passwd ); - mGxsMails = new p3GxsMails(gxsmail_ds, NULL, *mGxsIdService); - RsGxsNetService* gxsmails_ns = new RsGxsNetService( - RS_SERVICE_TYPE_GXS_MAIL, gxsmail_ds, nxsMgr, mGxsMails, - mGxsMails->getServiceInfo(), mReputations, mGxsCircles, + mGxsTrans = new p3GxsTrans(gxstrans_ds, NULL, *mGxsIdService); + RsGxsNetService* gxstrans_ns = new RsGxsNetService( + RS_SERVICE_TYPE_GXS_TRANS, gxstrans_ds, nxsMgr, mGxsTrans, + mGxsTrans->getServiceInfo(), mReputations, mGxsCircles, mGxsIdService, pgpAuxUtils); - mGxsMails->setNetworkExchangeService(gxsmails_ns); - pqih->addService(gxsmails_ns, true); -# ifdef TEST_RS_GXS_MAIL - TestGxsMailClientService* tgms = - new TestGxsMailClientService(*mGxsMails, *mGxsIdService); -# endif // TEST_RS_GXS_MAIL -# endif // RS_GXS_MAIL + mGxsTrans->setNetworkExchangeService(gxstrans_ns); + pqih->addService(gxstrans_ns, true); +# endif // RS_GXS_TRANS // remove pword from memory rsInitConfig->gxs_passwd = ""; @@ -1510,9 +1506,9 @@ int RsServer::StartupRetroShare() p3ServiceInfo *serviceInfo = new p3ServiceInfo(serviceCtrl); mDisc = new p3discovery2(mPeerMgr, mLinkMgr, mNetMgr, serviceCtrl); mHeart = new p3heartbeat(serviceCtrl, pqih); - msgSrv = new p3MsgService( serviceCtrl, mGxsIdService, *mGxsMails ); + msgSrv = new p3MsgService( serviceCtrl, mGxsIdService, *mGxsTrans ); chatSrv = new p3ChatService( serviceCtrl,mGxsIdService, mLinkMgr, - mHistoryMgr, *mGxsMails ); + mHistoryMgr, *mGxsTrans ); mStatusSrv = new p3StatusService(serviceCtrl); #ifdef ENABLE_GROUTER @@ -1678,10 +1674,10 @@ int RsServer::StartupRetroShare() #ifdef RS_ENABLE_GXS -# ifdef RS_GXS_MAIL - mConfigMgr->addConfiguration("gxs_mail_ns.cfg", gxsmails_ns); - mConfigMgr->addConfiguration("gxs_mail.cfg", mGxsMails); -# endif +# ifdef RS_GXS_TRANS + mConfigMgr->addConfiguration("gxs_trans_ns.cfg", gxstrans_ns); + mConfigMgr->addConfiguration("gxs_trans.cfg", mGxsTrans); +# endif // RS_GXS_TRANS mConfigMgr->addConfiguration("p3identity.cfg", mGxsIdService); @@ -1830,13 +1826,10 @@ int RsServer::StartupRetroShare() //createThread(*photo_ns); //createThread(*wire_ns); -# ifdef RS_GXS_MAIL - startServiceThread(mGxsMails, "gxs mail"); - startServiceThread(gxsmails_ns, "gxs mail ns"); -# ifdef TEST_RS_GXS_MAIL - tgms->start("Gxs Mail Test Service"); -# endif // TEST_RS_GXS_MAIL -# endif // RS_GXS_MAIL +# ifdef RS_GXS_TRANS + startServiceThread(mGxsTrans, "gxs trans"); + startServiceThread(gxstrans_ns, "gxs trans ns"); +# endif // RS_GXS_TRANS #endif // RS_ENABLE_GXS diff --git a/libretroshare/src/serialiser/rsserviceids.h b/libretroshare/src/serialiser/rsserviceids.h index 1307ec53a..e3fc4a298 100644 --- a/libretroshare/src/serialiser/rsserviceids.h +++ b/libretroshare/src/serialiser/rsserviceids.h @@ -82,7 +82,7 @@ const uint16_t RS_SERVICE_GXS_TYPE_GXSCIRCLE = 0x0218; // not gxs, but used with identities. const uint16_t RS_SERVICE_GXS_TYPE_REPUTATION = 0x0219; const uint16_t RS_SERVICE_TYPE_GXS_RECOGN = 0x0220; -const uint16_t RS_SERVICE_TYPE_GXS_MAIL = 0x0230; +const uint16_t RS_SERVICE_TYPE_GXS_TRANS = 0x0230; // Experimental Services. /* DSDV Testing at the moment - Service Only */ diff --git a/libretroshare/src/services/p3msgservice.cc b/libretroshare/src/services/p3msgservice.cc index 7d33b2235..b93d888b4 100644 --- a/libretroshare/src/services/p3msgservice.cc +++ b/libretroshare/src/services/p3msgservice.cc @@ -86,12 +86,12 @@ static const uint32_t RS_MSG_DISTANT_MESSAGE_HASH_KEEP_TIME = 2*30*86400 ; // ke */ p3MsgService::p3MsgService( p3ServiceControl *sc, p3IdService *id_serv, - p3GxsMails& gxsMS ) + p3GxsTrans& gxsMS ) : p3Service(), p3Config(), gxsOngoingMutex("p3MsgService Gxs Outgoing Mutex"), mIdService(id_serv), mServiceCtrl(sc), mMsgMtx("p3MsgService"), mMsgUniqueId(0), recentlyReceivedMutex("p3MsgService recently received hash mutex"), - gxsMailService(gxsMS) + mGxsTransServ(gxsMS) { /* this serialiser is used for services. It's not the same than the one * returned by setupSerialiser(). We need both!! */ @@ -108,8 +108,8 @@ p3MsgService::p3MsgService( p3ServiceControl *sc, p3IdService *id_serv, if(sc) initStandardTagTypes(); // Initialize standard tag types - gxsMailService.registerGxsMailsClient( GxsMailSubServices::P3_MSG_SERVICE, - this ); + mGxsTransServ.registerGxsTransClient( GxsTransSubServices::P3_MSG_SERVICE, + this ); } const std::string MSG_APP_NAME = "msg"; @@ -1990,12 +1990,12 @@ uint32_t p3MsgService::getDistantMessagingPermissionFlags() return mDistantMessagePermissions ; } -bool p3MsgService::receiveGxsMail( const RsGxsId& authorId, - const RsGxsId& recipientId, - const uint8_t* data, uint32_t dataSize ) +bool p3MsgService::receiveGxsTransMail( const RsGxsId& authorId, + const RsGxsId& recipientId, + const uint8_t* data, uint32_t dataSize ) { - std::cout << "p3MsgService::receiveGxsMail(" << authorId - << ", " << recipientId << ", " << dataSize << ")" << std::endl; + std::cout << __PRETTY_FUNCTION__ << " " << authorId << ", " << recipientId + << ",, " << dataSize << std::endl; Sha1CheckSum hash = RsDirUtil::sha1sum(data, dataSize); @@ -2004,7 +2004,7 @@ bool p3MsgService::receiveGxsMail( const RsGxsId& authorId, if( mRecentlyReceivedMessageHashes.find(hash) != mRecentlyReceivedMessageHashes.end() ) { - std::cerr << "p3MsgService::receiveGxsMail(...) (II) receiving " + std::cerr << __PRETTY_FUNCTION__ << " (II) receiving " << "message of hash " << hash << " more than once. " << "Probably it has arrived before by other means." << std::endl; @@ -2020,8 +2020,8 @@ bool p3MsgService::receiveGxsMail( const RsGxsId& authorId, if(msg_item) { - std::cerr << "p3MsgService::receiveGxsMail(...) Encrypted item " - << "correctly deserialised. Passing on to incoming list." + std::cerr << __PRETTY_FUNCTION__ << " Encrypted item correctly " + << "deserialised. Passing on to incoming list." << std::endl; msg_item->msgFlags |= RS_MSG_FLAGS_DISTANT; @@ -2035,7 +2035,7 @@ bool p3MsgService::receiveGxsMail( const RsGxsId& authorId, } else { - std::cerr << "p3MsgService::receiveGxsMail(...) Item could not be " + std::cerr << __PRETTY_FUNCTION__ << " Item could not be " << "deserialised. Format error??" << std::endl; return false; } @@ -2043,26 +2043,26 @@ bool p3MsgService::receiveGxsMail( const RsGxsId& authorId, return true; } -bool p3MsgService::notifySendMailStatus( const RsGxsMailItem& originalMessage, - GxsMailStatus status ) +bool p3MsgService::notifyGxsTransSendStatus( RsGxsTransId mailId, + GxsTransSendStatus status ) { - std::cout << "p3MsgService::notifySendMailStatus(" << originalMessage.mailId - << ", " << static_cast(status) << ")" << std::endl; + std::cout << __PRETTY_FUNCTION__ << " " << mailId << ", " + << static_cast(status) << std::endl; - if( status == GxsMailStatus::RECEIPT_RECEIVED ) + if( status == GxsTransSendStatus::RECEIPT_RECEIVED ) { uint32_t msg_id; { RS_STACK_MUTEX(gxsOngoingMutex); - auto it = gxsOngoingMessages.find(originalMessage.mailId); + auto it = gxsOngoingMessages.find(mailId); if(it == gxsOngoingMessages.end()) { - std::cerr << "p3MsgService::notifySendMailStatus(" - << originalMessage.mailId - << ", " << static_cast(status) << ") " - << "(EE) cannot find pending message to acknowledge!" + std::cerr << __PRETTY_FUNCTION__<< " " + << mailId + << ", " << static_cast(status) + << " (EE) cannot find pending message to acknowledge!" << std::endl; return false; } @@ -2078,9 +2078,8 @@ bool p3MsgService::notifySendMailStatus( const RsGxsMailItem& originalMessage, auto it2 = msgOutgoing.find(msg_id); if(it2 == msgOutgoing.end()) { - std::cerr << "p3MsgService::notifySendMailStatus(" - << originalMessage.mailId - << ", " << static_cast(status) << ") (II) " + std::cerr << __PRETTY_FUNCTION__ << " " << mailId + << ", " << static_cast(status) << " (II) " << "received receipt for message that is not in " << "outgoing list, probably it has been acknoweldged " << "before by other means." << std::endl; @@ -2098,18 +2097,18 @@ bool p3MsgService::notifySendMailStatus( const RsGxsMailItem& originalMessage, return true; } - if( status >= GxsMailStatus::FAILED_RECEIPT_SIGNATURE ) + if( status >= GxsTransSendStatus::FAILED_RECEIPT_SIGNATURE ) { uint32_t msg_id; { RS_STACK_MUTEX(gxsOngoingMutex); - std::cerr << "p3MsgService::notifySendMailStatus(...) mail delivery" - << "mailId: " << originalMessage.mailId + std::cerr << __PRETTY_FUNCTION__ << " mail delivery " + << "mailId: " << mailId << " failed with " << static_cast(status); - auto it = gxsOngoingMessages.find(originalMessage.mailId); + auto it = gxsOngoingMessages.find(mailId); if(it == gxsOngoingMessages.end()) { std::cerr << " cannot find pending message to notify" @@ -2258,8 +2257,8 @@ void p3MsgService::sendDistantMsgItem(RsMsgItem *msgitem) mGRouter->sendData( destination_key_id, GROUTER_CLIENT_ID_MESSAGES, msg_serialized_data, msg_serialized_rssize, signing_key_id, grouter_message_id ); - RsGxsMailId gxsMailId; - gxsMailService.sendMail( gxsMailId, GxsMailSubServices::P3_MSG_SERVICE, + RsGxsTransId gxsMailId; + mGxsTransServ.sendMail( gxsMailId, GxsTransSubServices::P3_MSG_SERVICE, signing_key_id, destination_key_id, msg_serialized_data, msg_serialized_rssize ); diff --git a/libretroshare/src/services/p3msgservice.h b/libretroshare/src/services/p3msgservice.h index 8846c3f9a..50628a774 100644 --- a/libretroshare/src/services/p3msgservice.h +++ b/libretroshare/src/services/p3msgservice.h @@ -49,7 +49,7 @@ #include "grouter/grouterclientservice.h" #include "turtle/p3turtle.h" #include "turtle/turtleclientservice.h" -#include "services/p3gxsmails.h" +#include "gxstrans/p3gxstrans.h" class p3LinkMgr; class p3IdService; @@ -57,9 +57,9 @@ class p3IdService; // Temp tweak to test grouter struct p3MsgService : p3Service, p3Config, pqiServiceMonitor, GRouterClientService, - GxsMailsClient + GxsTransClient { - p3MsgService(p3ServiceControl *sc, p3IdService *id_service, p3GxsMails& gxsMS); + p3MsgService(p3ServiceControl *sc, p3IdService *id_service, p3GxsTrans& gxsMS); virtual RsServiceInfo getServiceInfo(); @@ -135,14 +135,14 @@ struct p3MsgService : void setDistantMessagingPermissionFlags(uint32_t flags) ; uint32_t getDistantMessagingPermissionFlags() ; - /// @see GxsMailsClient::receiveGxsMail(...) - virtual bool receiveGxsMail( const RsGxsId& authorId, - const RsGxsId& recipientId, - const uint8_t* data, uint32_t dataSize ); + /// @see GxsTransClient::receiveGxsTransMail(...) + virtual bool receiveGxsTransMail( const RsGxsId& authorId, + const RsGxsId& recipientId, + const uint8_t* data, uint32_t dataSize ); - /// @see GxsMailsClient::notifySendMailStatus(...) - virtual bool notifySendMailStatus( const RsGxsMailItem& originalMessage, - GxsMailStatus status ); + /// @see GxsTransClient::notifyGxsTransSendStatus(...) + virtual bool notifyGxsTransSendStatus( RsGxsTransId mailId, + GxsTransSendStatus status ); private: void sendDistantMsgItem(RsMsgItem *msgitem); @@ -152,7 +152,7 @@ private: std::map _ongoing_messages; /// Contains ongoing messages handed to gxs mail - std::map gxsOngoingMessages; + std::map gxsOngoingMessages; RsMutex gxsOngoingMutex; // Overloaded from GRouterClientService @@ -229,7 +229,7 @@ private: uint32_t mDistantMessagePermissions ; bool mShouldEnableDistantMessaging ; - p3GxsMails& gxsMailService; + p3GxsTrans& mGxsTransServ; }; #endif // MESSAGE_SERVICE_HEADER diff --git a/retroshare.pri b/retroshare.pri index 05ccf0469..99f3e4f04 100644 --- a/retroshare.pri +++ b/retroshare.pri @@ -61,9 +61,9 @@ CONFIG *= no_rs_nocppwarning rs_nocppwarning:CONFIG -= no_rs_nocppwarning # To disable GXS mail append the following assignation to qmake command line -# "CONFIG+=no_rs_gxs_mail" -CONFIG *= rs_gxs_mail -#no_rs_gxs_mail:CONFIG -= rs_gxs_mail ## Disabing not supported ATM +# "CONFIG+=no_rs_gxs_trans" +CONFIG *= rs_gxs_trans +#no_rs_gxs_trans:CONFIG -= rs_gxs_trans ## Disabing not supported ATM unix { @@ -173,17 +173,17 @@ rs_nodeprecatedwarning { QMAKE_CXXFLAGS += -Wno-deprecated QMAKE_CXXFLAGS += -Wno-deprecated-declarations DEFINES *= RS_NO_WARN_DEPRECATED - warning("QMAKE: You have disable deprecated warnings.") + warning("QMAKE: You have disabled deprecated warnings.") } rs_nocppwarning { QMAKE_CXXFLAGS += -Wno-cpp DEFINES *= RS_NO_WARN_CPP - warning("QMAKE: You have disable C preprocessor warnings.") + warning("QMAKE: You have disabled C preprocessor warnings.") } -rs_gxs_mail { - DEFINES *= RS_GXS_MAIL +rs_gxs_trans { + DEFINES *= RS_GXS_TRANS greaterThan(QT_MAJOR_VERSION, 4) { CONFIG += c++11 } else { From 5c434fb10735937e937ef5956ff447d0fd02f474 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Fri, 3 Mar 2017 12:21:43 +0100 Subject: [PATCH 30/35] Fix typos reported by Jums --- libretroshare/src/gxstrans/p3gxstrans.cc | 10 ++++++---- libretroshare/src/gxstrans/p3gxstrans.h | 2 +- libretroshare/src/gxstrans/p3gxstransitems.cc | 2 +- libretroshare/src/gxstrans/p3gxstransitems.h | 6 +++--- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/libretroshare/src/gxstrans/p3gxstrans.cc b/libretroshare/src/gxstrans/p3gxstrans.cc index dab362ce2..b36a6ade6 100644 --- a/libretroshare/src/gxstrans/p3gxstrans.cc +++ b/libretroshare/src/gxstrans/p3gxstrans.cc @@ -248,7 +248,8 @@ void p3GxsTrans::service_tick() { case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_MAIL: { - RsGxsTransMailItem* msg = dynamic_cast(it->second); + RsGxsTransMailItem* msg = + dynamic_cast(it->second); if(!msg) { std::cerr << "p3GxsTrans::service_tick() (EE) " @@ -267,7 +268,7 @@ void p3GxsTrans::service_tick() << " mailId: "<< msg->mailId << " payload.size(): " << msg->payload.size() << std::endl; - handleEcryptedMail(msg); + handleEncryptedMail(msg); } break; } @@ -398,7 +399,7 @@ bool p3GxsTrans::requestGroupsData(const std::list* groupIds) return true; } -bool p3GxsTrans::handleEcryptedMail(const RsGxsTransMailItem* mail) +bool p3GxsTrans::handleEncryptedMail(const RsGxsTransMailItem* mail) { std::cout << "p3GxsTrans::handleEcryptedMail(...)" << std::endl; @@ -411,7 +412,8 @@ bool p3GxsTrans::handleEcryptedMail(const RsGxsTransMailItem* mail) // Hint match none of our own ids if(decryptIds.empty()) { - std::cout << "p3GxsTrans::handleEcryptedMail(...) hint doesn't match" << std::endl; + std::cout << "p3GxsTrans::handleEcryptedMail(...) hint doesn't match" + << std::endl; return true; } diff --git a/libretroshare/src/gxstrans/p3gxstrans.h b/libretroshare/src/gxstrans/p3gxstrans.h index d03806f72..affaaa638 100644 --- a/libretroshare/src/gxstrans/p3gxstrans.h +++ b/libretroshare/src/gxstrans/p3gxstrans.h @@ -242,7 +242,7 @@ private: /// Decrypt email content and pass it to dispatchDecryptedMail(...) - bool handleEcryptedMail(const RsGxsTransMailItem* mail); + bool handleEncryptedMail(const RsGxsTransMailItem* mail); /// Dispatch the message to the recipient service bool dispatchDecryptedMail( const RsGxsId& authorId, diff --git a/libretroshare/src/gxstrans/p3gxstransitems.cc b/libretroshare/src/gxstrans/p3gxstransitems.cc index 886760215..eb5736f8e 100644 --- a/libretroshare/src/gxstrans/p3gxstransitems.cc +++ b/libretroshare/src/gxstrans/p3gxstransitems.cc @@ -129,7 +129,7 @@ OutgoingRecord::OutgoingRecord() : static_cast(GxsTransItemsSubtypes::OUTGOING_RECORD_ITEM) ) { clear();} -uint32_t OutgoingRecord::size() const +uint32_t OutgoingRecord::serial_size() const { return 8 + // Header 1 + // status diff --git a/libretroshare/src/gxstrans/p3gxstransitems.h b/libretroshare/src/gxstrans/p3gxstransitems.h index 3f3d38145..fa6395f3b 100644 --- a/libretroshare/src/gxstrans/p3gxstransitems.h +++ b/libretroshare/src/gxstrans/p3gxstransitems.h @@ -120,7 +120,7 @@ struct RsGxsTransMailItem : RsGxsTransBaseItem * * To check if one id may be the recipient of the mail or not one need to * bitwise compare the hint with the id, if at least one bit of the hint is - * 0 while the corrisponding bit in the id is 1 then the id cannot be the + * 0 while the corresponding bit in the id is 1 then the id cannot be the * recipient of the mail. * * Note that by design one can prove that an id is not recipient of the mail @@ -253,7 +253,7 @@ struct OutgoingRecord : RsItem GxsTransSubServices clientService; RsNxsTransPresignedReceipt presignedReceipt; - uint32_t size() const; + uint32_t serial_size() const; bool serialize(uint8_t* data, uint32_t size, uint32_t& offset) const; bool deserialize(const uint8_t* data, uint32_t& size, uint32_t& offset); @@ -289,7 +289,7 @@ struct RsGxsTransSerializer : RsSerialType case GxsTransItemsSubtypes::OUTGOING_RECORD_ITEM: { OutgoingRecord* ci = dynamic_cast(item); - if(ci) sz = ci->size(); + if(ci) sz = ci->serial_size(); break; } default: break; From f7f36f697e8d139691fe0715397d95afe1492329 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Fri, 5 May 2017 17:52:44 +0200 Subject: [PATCH 31/35] fixup! Merge branch 'master' into gxs_mail_experiments --- libretroshare/src/rsitems/rsnxsitems.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/libretroshare/src/rsitems/rsnxsitems.h b/libretroshare/src/rsitems/rsnxsitems.h index 247e664fa..127d876f6 100644 --- a/libretroshare/src/rsitems/rsnxsitems.h +++ b/libretroshare/src/rsitems/rsnxsitems.h @@ -372,8 +372,6 @@ struct RsNxsMsg : RsNxsItem msg(servtype), metaData(NULL) { clear(); } virtual ~RsNxsMsg() { delete metaData; } - virtual void clear(); - virtual void serial_process( RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext& ctx ); From ea8f800003330eaabb576092a1697b79eb96bfc8 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Mon, 8 May 2017 00:19:11 +0200 Subject: [PATCH 32/35] Port GxsTrans to new serialization system RsItem added some comment and more verbose error reporting RsTypeSerializer added support for RsItem derived classes as members added utility macros for better readability of the code and easier handling of RsItem derived members RS_REGISTER_SERIAL_MEMBER(I) RS_REGISTER_SERIAL_MEMBER_TYPED(I, T) RS_REGISTER_ITEM_TYPE(T) RsNxsMsg::serial_process use new macros for better readability and to have an exemple of usage with RsTlvItem derived class Fix undefined reference to RsNxsMsg::print --- libretroshare/src/chat/p3chatservice.cc | 9 +- libretroshare/src/chat/rschatitems.cc | 7 + libretroshare/src/chat/rschatitems.h | 11 + libretroshare/src/gxstrans/p3gxstrans.cc | 20 +- libretroshare/src/gxstrans/p3gxstransitems.cc | 193 +--- libretroshare/src/gxstrans/p3gxstransitems.h | 167 +--- libretroshare/src/rsitems/rsitem.h | 25 +- libretroshare/src/rsitems/rsnxsitems.cc | 26 +- libretroshare/src/rsitems/rsnxsitems.h | 2 +- .../src/serialiser/rstypeserializer.cc | 56 ++ .../src/serialiser/rstypeserializer.h | 867 ++++++++++-------- 11 files changed, 655 insertions(+), 728 deletions(-) diff --git a/libretroshare/src/chat/p3chatservice.cc b/libretroshare/src/chat/p3chatservice.cc index 3798666e5..32dbe64a5 100644 --- a/libretroshare/src/chat/p3chatservice.cc +++ b/libretroshare/src/chat/p3chatservice.cc @@ -346,9 +346,9 @@ bool p3ChatService::sendChat(ChatId destination, std::string msg) if(it != mDistantGxsMap.end()) { const DistantEndpoints& de(it->second); - uint32_t sz = ci->serial_size(); + uint32_t sz = _serializer->size(ci); std::vector data; data.resize(sz); - ci->serialise(&data[0], sz); + _serializer->serialise(ci, &data[0], &sz); mGxsTransport.sendMail(tId, GxsTransSubServices::P3_CHAT_SERVICE, de.from, de.to, &data[0], sz); } @@ -717,8 +717,9 @@ bool p3ChatService::receiveGxsTransMail( const RsGxsId& authorId, if(initiateDistantChatConnexion( authorId, recipientId, pid, error_code, false )) { - RsChatMsgItem* item = new RsChatMsgItem( const_cast(data), - dataSize ); + RsChatMsgItem* item = static_cast( + _serializer->deserialise( + const_cast(data), &dataSize )); RsPeerId rd(p3GxsTunnelService::makeGxsTunnelId(authorId, recipientId)); item->PeerId(rd); handleRecvChatMsgItem(item); diff --git a/libretroshare/src/chat/rschatitems.cc b/libretroshare/src/chat/rschatitems.cc index 2b7dd67d8..35ccaa905 100644 --- a/libretroshare/src/chat/rschatitems.cc +++ b/libretroshare/src/chat/rschatitems.cc @@ -195,4 +195,11 @@ void RsPrivateChatMsgConfigItem::get(RsChatMsgItem *ci) ci->recvTime = recvTime; } +/* Necessary to serialize `store` that is an STL container with RsChatMsgItem + * inside which is a subtype of RsItem */ +RS_REGISTER_ITEM_TYPE(RsChatMsgItem) +void PrivateOugoingMapItem::serial_process( + RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ) +{ RS_REGISTER_SERIAL_MEMBER(store); } diff --git a/libretroshare/src/chat/rschatitems.h b/libretroshare/src/chat/rschatitems.h index 617ca3276..253bb66f1 100644 --- a/libretroshare/src/chat/rschatitems.h +++ b/libretroshare/src/chat/rschatitems.h @@ -325,6 +325,17 @@ class RsChatAvatarItem: public RsChatItem unsigned char *image_data ; // image }; + +struct PrivateOugoingMapItem : RsChatItem +{ + PrivateOugoingMapItem() : RsChatItem(RS_PKT_SUBTYPE_OUTGOING_MAP) {} + + void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ); + + std::map store; +}; + struct RsChatSerialiser : RsServiceSerializer { RsChatSerialiser(SerializationFlags flags = SERIALIZATION_FLAG_NONE) : diff --git a/libretroshare/src/gxstrans/p3gxstrans.cc b/libretroshare/src/gxstrans/p3gxstrans.cc index b36a6ade6..4454bf6e1 100644 --- a/libretroshare/src/gxstrans/p3gxstrans.cc +++ b/libretroshare/src/gxstrans/p3gxstrans.cc @@ -478,14 +478,16 @@ bool p3GxsTrans::dispatchDecryptedMail( const RsGxsId& authorId, } GxsTransSubServices rsrvc = static_cast(csri); - RsNxsTransPresignedReceipt* receipt = new RsNxsTransPresignedReceipt(); uint32_t rcptsize = decrypted_data_size; - if(!receipt->deserialize(decrypted_data, rcptsize, offset)) + RsNxsTransPresignedReceipt* receipt = + static_cast( + RsGxsTransSerializer().deserialise( + const_cast(decrypted_data), &rcptsize ) ); + if(!receipt) { std::cerr << "p3GxsTrans::dispatchDecryptedMail(...) (EE) fatal error " << "deserializing presigned return receipt , something really" << " wrong is happening!" << std::endl; - delete receipt; return false; } std::cout << "p3GxsTrans::dispatchDecryptedMail(...) dispatching receipt " @@ -541,10 +543,10 @@ void p3GxsTrans::processOutgoingRecord(OutgoingRecord& pr) grcpt.meta = pr.mailItem.meta; grcpt.meta.mPublishTs = time(NULL); grcpt.mailId = pr.mailItem.mailId; - uint32_t groff = 0, grsz = grcpt.serial_size(); + uint32_t grsz = RsGxsTransSerializer().size(&grcpt); std::vector grsrz; grsrz.resize(grsz); - grcpt.serialize(&grsrz[0], grsz, groff); + RsGxsTransSerializer().serialise(&grcpt, &grsrz[0], &grsz); pr.presignedReceipt.grpId = mPreferredGroupId; pr.presignedReceipt.metaData = new RsGxsMsgMetaData(); @@ -572,13 +574,14 @@ void p3GxsTrans::processOutgoingRecord(OutgoingRecord& pr) case GxsTransSendStatus::PENDING_PAYLOAD_CREATE: { uint16_t serv = static_cast(pr.clientService); - uint32_t rcptsize = pr.presignedReceipt.serial_size(); + uint32_t rcptsize = RsGxsTransSerializer().size(&pr.presignedReceipt); uint32_t datasize = pr.mailData.size(); pr.mailItem.payload.resize(2 + rcptsize + datasize); uint32_t offset = 0; setRawUInt16(&pr.mailItem.payload[0], 2, &offset, serv); - pr.presignedReceipt.serialise( &pr.mailItem.payload[offset], - rcptsize ); + RsGxsTransSerializer().serialise(&pr.presignedReceipt, + &pr.mailItem.payload[offset], + &rcptsize); offset += rcptsize; memcpy(&pr.mailItem.payload[offset], &pr.mailData[0], datasize); } @@ -781,4 +784,3 @@ bool p3GxsTrans::loadList(std::list&loadList) return true; } - diff --git a/libretroshare/src/gxstrans/p3gxstransitems.cc b/libretroshare/src/gxstrans/p3gxstransitems.cc index eb5736f8e..cab1e2dfb 100644 --- a/libretroshare/src/gxstrans/p3gxstransitems.cc +++ b/libretroshare/src/gxstrans/p3gxstransitems.cc @@ -17,88 +17,14 @@ */ #include "gxstrans/p3gxstransitems.h" +#include "serialiser/rstypeserializer.h" const RsGxsId RsGxsTransMailItem::allRecipientsHint("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); - -bool RsGxsTransBaseItem::serialize(uint8_t* data, uint32_t size, - uint32_t& offset) const -{ - bool ok = setRsItemHeader(data+offset, size, PacketId(), size); - ok = ok && (offset += 8); // Take header in account - ok = ok && setRawUInt64(data, size, &offset, mailId); - return ok; -} - -bool RsGxsTransBaseItem::deserialize( const uint8_t* data, uint32_t& size, - uint32_t& offset) -{ - void* hdrPtr = const_cast(data+offset); - uint32_t rssize = getRsItemSize(hdrPtr); - uint32_t roffset = offset + 8; // Take header in account - - void* dataPtr = const_cast(data); - bool ok = rssize <= size; - ok = ok && getRawUInt64(dataPtr, rssize, &roffset, &mailId); - if(ok) { size = rssize; offset = roffset; } - else size = 0; - return ok; -} - -std::ostream& RsGxsTransBaseItem::print(std::ostream &out, uint16_t) -{ return out << __PRETTY_FUNCTION__ << " mailId: " << mailId; } - -bool RsGxsTransSerializer::serialise(RsItem* item, void* data, uint32_t* size) -{ - uint32_t itemSize = RsGxsTransSerializer::size(item); - if(*size < itemSize) - { - std::cout << __PRETTY_FUNCTION__ << " failed due to wrong size: " - << size << " < " << itemSize << std::endl; - return false; - } - - uint8_t* dataPtr = reinterpret_cast(data); - bool ok = false; - switch(static_cast(item->PacketSubType())) - { - case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_MAIL: - { - uint32_t offset = 0; - RsGxsTransMailItem* i = dynamic_cast(item); - ok = i && i->serialize(dataPtr, itemSize, offset); - break; - } - case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_RECEIPT: - { - RsGxsTransPresignedReceipt* i = - dynamic_cast(item); - uint32_t offset = 0; - ok = i && i->serialize(dataPtr, itemSize, offset); - break; - } - case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_GROUP: - ok = setRsItemHeader(data, itemSize, item->PacketId(), itemSize); - break; - case GxsTransItemsSubtypes::OUTGOING_RECORD_ITEM: - { - uint32_t offset = 0; - OutgoingRecord* i = dynamic_cast(item); - ok = i && i->serialize(dataPtr, itemSize, offset); - break; - } - default: ok = false; break; - } - - if(ok) - { - *size = itemSize; - return true; - } - - std::cout << __PRETTY_FUNCTION__ << " failed!" << std::endl; - return false; -} +OutgoingRecord::OutgoingRecord() : + RsItem( RS_PKT_VERSION_SERVICE, RS_SERVICE_TYPE_GXS_TRANS, + static_cast(GxsTransItemsSubtypes::OUTGOING_RECORD_ITEM) ) +{ clear();} OutgoingRecord::OutgoingRecord( RsGxsId rec, GxsTransSubServices cs, const uint8_t* data, uint32_t size ) : @@ -111,102 +37,17 @@ OutgoingRecord::OutgoingRecord( RsGxsId rec, GxsTransSubServices cs, memcpy(&mailData[0], data, size); } -void OutgoingRecord::clear() + +RS_REGISTER_ITEM_TYPE(RsGxsTransMailItem) // for mailItem +RS_REGISTER_ITEM_TYPE(RsNxsTransPresignedReceipt) // for presignedReceipt + +void OutgoingRecord::serial_process(RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx) { - status = GxsTransSendStatus::UNKNOWN; - recipient.clear(); - mailItem.clear(); - mailData.clear(); - clientService = GxsTransSubServices::UNKNOWN; - presignedReceipt.clear(); + RS_REGISTER_SERIAL_MEMBER_TYPED(status, uint8_t); + RS_REGISTER_SERIAL_MEMBER(recipient); + RS_REGISTER_SERIAL_MEMBER(mailItem); + RS_REGISTER_SERIAL_MEMBER(mailData); + RS_REGISTER_SERIAL_MEMBER_TYPED(clientService, uint16_t); + RS_REGISTER_SERIAL_MEMBER(presignedReceipt); } - -std::ostream& OutgoingRecord::print(std::ostream& out, uint16_t) -{ return out << "TODO: OutgoingRecordItem::print(...)"; } - -OutgoingRecord::OutgoingRecord() : - RsItem( RS_PKT_VERSION_SERVICE, RS_SERVICE_TYPE_GXS_TRANS, - static_cast(GxsTransItemsSubtypes::OUTGOING_RECORD_ITEM) ) -{ clear();} - -uint32_t OutgoingRecord::serial_size() const -{ - return 8 + // Header - 1 + // status - recipient.serial_size() + - mailItem.serial_size() + - 4 + // sizeof(mailData.size()) - mailData.size() + - 2 + // clientService - presignedReceipt.serial_size(); -} - -bool OutgoingRecord::serialize( uint8_t* data, uint32_t size, - uint32_t& offset) const -{ - bool ok = true; - - ok = ok && setRsItemHeader(data+offset, size, PacketId(), size) - && (offset += 8); // Take header in account - - ok = ok && setRawUInt8(data, size, &offset, static_cast(status)); - - ok = ok && recipient.serialise(data, size, offset); - - uint32_t tmpOffset = 0; - uint32_t tmpSize = mailItem.serial_size(); - ok = ok && mailItem.serialize(data+offset, tmpSize, tmpOffset) - && (offset += tmpOffset); - - uint32_t dSize = mailData.size(); - ok = ok && setRawUInt32(data, size, &offset, dSize) - && memcpy(data+offset, &mailData[0], dSize) && (offset += dSize); - - ok = ok && setRawUInt16( data, size, &offset, - static_cast(clientService) ); - - dSize = presignedReceipt.serial_size(); - ok = ok && presignedReceipt.serialise(data+offset, dSize) - && (offset += dSize); - - return ok; -} - -bool OutgoingRecord::deserialize( - const uint8_t* data, uint32_t& size, uint32_t& offset) -{ - bool ok = true; - - void* dataPtr = const_cast(data); - offset += 8; // Header - - uint8_t tmpStatus = 0; - ok = ok && getRawUInt8(dataPtr, size, &offset, &tmpStatus); - status = static_cast(tmpStatus); - - uint32_t tmpSize = size; - ok = ok && recipient.deserialise(dataPtr, tmpSize, offset); - - void* hdrPtr = const_cast(data+offset); - tmpSize = getRsItemSize(hdrPtr); - - uint32_t tmpOffset = 0; - ok = ok && mailItem.deserialize(static_cast(hdrPtr), tmpSize, tmpOffset); - ok = ok && (offset += tmpOffset); - - tmpSize = size; - ok = getRawUInt32(dataPtr, tmpSize, &offset, &tmpSize); - ok = ok && (tmpSize+offset < size); - ok = ok && (mailData.resize(tmpSize), memcpy(&mailData[0], data, tmpSize)); - ok = ok && (offset += tmpSize); - - uint16_t cs = 0; - ok = ok && getRawUInt16(dataPtr, offset+2, &offset, &cs); - clientService = static_cast(cs); - - tmpSize = size; - ok = ok && presignedReceipt.deserialize(data, tmpSize, offset); - - return ok; -} - diff --git a/libretroshare/src/gxstrans/p3gxstransitems.h b/libretroshare/src/gxstrans/p3gxstransitems.h index fa6395f3b..276dd739e 100644 --- a/libretroshare/src/gxstrans/p3gxstransitems.h +++ b/libretroshare/src/gxstrans/p3gxstransitems.h @@ -19,12 +19,13 @@ #include -#include "serialiser/rsgxsitems.h" +#include "rsitems/rsgxsitems.h" #include "serialiser/rsbaseserial.h" #include "serialiser/rstlvidset.h" #include "retroshare/rsgxsflags.h" #include "retroshare/rsgxscircles.h" // For: GXS_CIRCLE_TYPE_PUBLIC #include "services/p3idservice.h" +#include "serialiser/rstypeserializer.h" /// Subservices identifiers (like port for TCP) enum class GxsTransSubServices : uint16_t @@ -65,14 +66,9 @@ struct RsGxsTransBaseItem : RsGxsMsgItem meta = RsMsgMetaData(); } - static uint32_t inline serial_size() - { - return 8 + // Header - 8; // mailId - } - bool serialize(uint8_t* data, uint32_t size, uint32_t& offset) const; - bool deserialize(const uint8_t* data, uint32_t& size, uint32_t& offset); - std::ostream &print(std::ostream &out, uint16_t /*indent = 0*/); + void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ) + { RS_REGISTER_SERIAL_MEMBER_TYPED(mailId, uint64_t); } }; struct RsGxsTransPresignedReceipt : RsGxsTransBaseItem @@ -149,46 +145,15 @@ struct RsGxsTransMailItem : RsGxsTransBaseItem * is specified */ std::vector payload; - uint32_t serial_size() const + void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ) { - return RsGxsTransBaseItem::serial_size() + - 1 + // cryptoType - recipientHint.serial_size() + - payload.size(); + RsGxsTransBaseItem::serial_process(j, ctx); + RS_REGISTER_SERIAL_MEMBER_TYPED(cryptoType, uint8_t); + RS_REGISTER_SERIAL_MEMBER(recipientHint); + RS_REGISTER_SERIAL_MEMBER(payload); } - bool serialize(uint8_t* data, uint32_t size, uint32_t& offset) const - { - bool ok = size < MAX_SIZE; - ok = ok && RsGxsTransBaseItem::serialize(data, size, offset); - ok = ok && setRawUInt8( data, size, &offset, - static_cast(cryptoType) ); - ok = ok && recipientHint.serialise(data, size, offset); - uint32_t psz = payload.size(); - ok = ok && memcpy(data+offset, &payload[0], psz); - offset += psz; - return ok; - } - bool deserialize(const uint8_t* data, uint32_t& size, uint32_t& offset) - { - void* sizePtr = const_cast(data+offset); - uint32_t rssize = getRsItemSize(sizePtr); - uint32_t roffset = offset; - bool ok = rssize <= size && size < MAX_SIZE; - ok = ok && RsGxsTransBaseItem::deserialize(data, rssize, roffset); - - void* dataPtr = const_cast(data); - uint8_t crType; - ok = ok && getRawUInt8(dataPtr, rssize, &roffset, &crType); - cryptoType = static_cast(crType); - ok = ok && recipientHint.deserialise(dataPtr, rssize, roffset); - uint32_t psz = rssize - roffset; - ok = ok && (payload.resize(psz), memcpy(&payload[0], data+roffset, psz)); - ok = ok && (roffset += psz); - if(ok) { size = rssize; offset = roffset; } - else size = 0; - return ok; - } void clear() { RsGxsTransBaseItem::clear(); @@ -213,6 +178,11 @@ struct RsGxsTransGroupItem : RsGxsGrpItem meta.mCircleType = GXS_CIRCLE_TYPE_PUBLIC; } + // TODO: Talk with Cyril why there is no RsGxsGrpItem::serial_process + virtual void serial_process(RsGenericSerializer::SerializeJob /*j*/, + RsGenericSerializer::SerializeContext& /*ctx*/) + {} + void clear() {} std::ostream &print(std::ostream &out, uint16_t /*indent = 0*/) { return out; } @@ -253,12 +223,10 @@ struct OutgoingRecord : RsItem GxsTransSubServices clientService; RsNxsTransPresignedReceipt presignedReceipt; - uint32_t serial_size() const; - bool serialize(uint8_t* data, uint32_t size, uint32_t& offset) const; - bool deserialize(const uint8_t* data, uint32_t& size, uint32_t& offset); + void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ); - virtual void clear(); - virtual std::ostream &print(std::ostream &out, uint16_t indent = 0); + void clear() {} private: friend class RsGxsTransSerializer; @@ -266,100 +234,23 @@ private: }; -struct RsGxsTransSerializer : RsSerialType +struct RsGxsTransSerializer : public RsServiceSerializer { - RsGxsTransSerializer() : RsSerialType( RS_PKT_VERSION_SERVICE, - RS_SERVICE_TYPE_GXS_TRANS ) {} + RsGxsTransSerializer() : RsServiceSerializer(RS_SERVICE_TYPE_GXS_TRANS) {} ~RsGxsTransSerializer() {} - uint32_t size(RsItem* item) + RsItem* create_item(uint16_t service_id, uint8_t item_sub_id) const { - uint32_t sz = 0; - switch(static_cast(item->PacketSubType())) - { - case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_MAIL: - { - RsGxsTransMailItem* i = dynamic_cast(item); - if(i) sz = i->serial_size(); - break; - } - case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_RECEIPT: - sz = RsGxsTransPresignedReceipt::serial_size(); break; - case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_GROUP: sz = 8; break; - case GxsTransItemsSubtypes::OUTGOING_RECORD_ITEM: - { - OutgoingRecord* ci = dynamic_cast(item); - if(ci) sz = ci->serial_size(); - break; - } - default: break; - } + if(service_id != RS_SERVICE_TYPE_GXS_TRANS) return NULL; - return sz; - } - - bool serialise(RsItem* item, void* data, uint32_t* size); - - RsItem* deserialise(void* data, uint32_t* size) - { - uint32_t rstype = getRsItemId(data); - uint32_t rssize = getRsItemSize(data); - uint8_t pktv = getRsItemVersion(rstype); - uint16_t srvc = getRsItemService(rstype); - const uint8_t* dataPtr = reinterpret_cast(data); - - if ( (RS_PKT_VERSION_SERVICE != pktv) || // 0x02 - (RS_SERVICE_TYPE_GXS_TRANS != srvc) || // 0x0230 = 560 - (*size < rssize) ) + switch(static_cast(item_sub_id)) { - print_stacktrace(); - return NULL; + case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_MAIL: return new RsGxsTransMailItem(); + case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_RECEIPT: return new RsGxsTransPresignedReceipt(); + case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_GROUP: return new RsGxsTransGroupItem(); + case GxsTransItemsSubtypes::OUTGOING_RECORD_ITEM: return new OutgoingRecord(); + default: return NULL; } - - *size = rssize; - bool ok = true; - RsItem* ret = NULL; - - switch (static_cast(getRsItemSubType(rstype))) - { - case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_MAIL: - { - RsGxsTransMailItem* i = new RsGxsTransMailItem(); - uint32_t offset = 0; - ok = ok && i->deserialize(dataPtr, *size, offset); - ret = i; - break; - } - case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_RECEIPT: - { - RsGxsTransPresignedReceipt* i = new RsGxsTransPresignedReceipt(); - uint32_t offset = 0; - ok &= i->deserialize(dataPtr, *size, offset); - ret = i; - break; - } - case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_GROUP: - { - ret = new RsGxsTransGroupItem(); - break; - } - case GxsTransItemsSubtypes::OUTGOING_RECORD_ITEM: - { - OutgoingRecord* i = new OutgoingRecord(); - uint32_t offset = 0; - ok = ok && i->deserialize(dataPtr, *size, offset); - ret = i; - break; - } - default: - ok = false; - break; - } - - if(ok) return ret; - - delete ret; - return NULL; } }; diff --git a/libretroshare/src/rsitems/rsitem.h b/libretroshare/src/rsitems/rsitem.h index 8dbda2fb3..5698728a0 100644 --- a/libretroshare/src/rsitems/rsitem.h +++ b/libretroshare/src/rsitems/rsitem.h @@ -3,6 +3,7 @@ #include "util/smallobject.h" #include "retroshare/rstypes.h" #include "serialiser/rsserializer.h" +#include "util/stacktrace.h" class RsItem: public RsMemoryManagement::SmallObject { @@ -15,6 +16,8 @@ class RsItem: public RsMemoryManagement::SmallObject #endif virtual ~RsItem(); + + /// TODO: Do this make sense with the new serialization system? virtual void clear() = 0; virtual std::ostream &print(std::ostream &out, uint16_t /* indent */ = 0) @@ -48,21 +51,16 @@ class RsItem: public RsMemoryManagement::SmallObject inline void setPriorityLevel(uint8_t l) { _priority_level = l ;} /** - * @brief serialize this object to the given buffer - * @param Job to do: serialise or deserialize. - * @param data Chunk of memory were to dump the serialized data - * @param size Size of memory chunk - * @param offset Readed to determine at witch offset start writing data, - * written to inform caller were written data ends, the updated value - * is usually passed by the caller to serialize of another - * RsSerializable so it can write on the same chunk of memory just - * after where this RsSerializable has been serialized. - * @return true if serialization successed, false otherwise + * TODO: This should be made pure virtual as soon as all the codebase + * is ported to the new serialization system */ - - virtual void serial_process(RsGenericSerializer::SerializeJob /* j */,RsGenericSerializer::SerializeContext& /* ctx */) + virtual void serial_process(RsGenericSerializer::SerializeJob, + RsGenericSerializer::SerializeContext&)// = 0; { - std::cerr << "(EE) RsItem::serial_process() called by an item using new serialization classes, but not derived! Class is " << typeid(*this).name() << std::endl; + std::cerr << "(EE) RsItem::serial_process() called by an item using" + << "new serialization classes, but not derived! Class is " + << typeid(*this).name() << std::endl; + print_stacktrace(); } protected: @@ -71,6 +69,7 @@ class RsItem: public RsMemoryManagement::SmallObject uint8_t _priority_level ; }; +/// TODO: Do this make sense with the new serialization system? class RsRawItem: public RsItem { public: diff --git a/libretroshare/src/rsitems/rsnxsitems.cc b/libretroshare/src/rsitems/rsnxsitems.cc index 104935930..200d45391 100644 --- a/libretroshare/src/rsitems/rsnxsitems.cc +++ b/libretroshare/src/rsitems/rsnxsitems.cc @@ -69,15 +69,18 @@ void RsNxsSyncMsgItem::serial_process(RsGenericSerializer::SerializeJob j,RsGene RsTypeSerializer::serial_process (j,ctx,msgId ,"msgId") ; RsTypeSerializer::serial_process (j,ctx,authorId ,"authorId") ; } -void RsNxsMsg::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) + +void RsNxsMsg::serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ) { - RsTypeSerializer::serial_process (j,ctx,transactionNumber,"transactionNumber") ; - RsTypeSerializer::serial_process (j,ctx,pos ,"pos") ; - RsTypeSerializer::serial_process (j,ctx,msgId ,"msgId") ; - RsTypeSerializer::serial_process (j,ctx,grpId ,"grpId") ; - RsTypeSerializer::serial_process(j,ctx,msg ,"msg") ; - RsTypeSerializer::serial_process(j,ctx,meta ,"meta") ; + RS_REGISTER_SERIAL_MEMBER_TYPED(transactionNumber, uint32_t); + RS_REGISTER_SERIAL_MEMBER_TYPED(pos, uint8_t); + RS_REGISTER_SERIAL_MEMBER(msgId); + RS_REGISTER_SERIAL_MEMBER(grpId); + RS_REGISTER_SERIAL_MEMBER_TYPED(msg, RsTlvItem); + RS_REGISTER_SERIAL_MEMBER_TYPED(meta, RsTlvItem); } + void RsNxsGrp::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) { RsTypeSerializer::serial_process (j,ctx,transactionNumber,"transactionNumber") ; @@ -149,11 +152,14 @@ void RsNxsMsg::clear() meta.TlvClear(); } +std::ostream&RsNxsMsg::print(std::ostream& out, uint16_t /*indent*/) +{ return out; } + void RsNxsGrp::clear() { - grpId.clear(); - grp.TlvClear(); - meta.TlvClear(); + grpId.clear(); + grp.TlvClear(); + meta.TlvClear(); } void RsNxsSyncGrpReqItem::clear() diff --git a/libretroshare/src/rsitems/rsnxsitems.h b/libretroshare/src/rsitems/rsnxsitems.h index 127d876f6..6779989f4 100644 --- a/libretroshare/src/rsitems/rsnxsitems.h +++ b/libretroshare/src/rsitems/rsnxsitems.h @@ -376,7 +376,7 @@ struct RsNxsMsg : RsNxsItem RsGenericSerializer::SerializeContext& ctx ); virtual void clear(); - virtual std::ostream &print(std::ostream &out, uint16_t indent); + virtual std::ostream &print(std::ostream& out, uint16_t indent); uint8_t pos; /// used for splitting up msg uint8_t count; /// number of split up messages diff --git a/libretroshare/src/serialiser/rstypeserializer.cc b/libretroshare/src/serialiser/rstypeserializer.cc index f4cfc0d62..c2b8bd1c4 100644 --- a/libretroshare/src/serialiser/rstypeserializer.cc +++ b/libretroshare/src/serialiser/rstypeserializer.cc @@ -27,6 +27,8 @@ #include "serialiser/rsbaseserial.h" #include "serialiser/rstlvkeys.h" +#include "rsitems/rsitem.h" + #include "util/rsprint.h" #include @@ -306,3 +308,57 @@ template<> void RsTypeSerializer::print_data(const std::string& n, const RsTlvIt std::cerr << " [" << typeid(s).name() << "] " << n << std::endl; } + +//============================================================================// +// RsItem and derivated // +//============================================================================// + +template<> uint32_t RsTypeSerializer::serial_size(const RsItem& s) +{ + RsGenericSerializer::SerializeContext ctx( + NULL, 0, RsGenericSerializer::FORMAT_BINARY, + RsGenericSerializer::SERIALIZATION_FLAG_NONE ); + + ctx.mOffset = 8; // header size + const_cast(s).serial_process(RsGenericSerializer::SIZE_ESTIMATE, + ctx); + + return ctx.mOffset; +} + +template<> bool RsTypeSerializer::serialize( uint8_t data[], uint32_t size, + uint32_t &offset, const RsItem& s ) +{ + RsGenericSerializer::SerializeContext ctx( + data, size, RsGenericSerializer::FORMAT_BINARY, + RsGenericSerializer::SERIALIZATION_FLAG_NONE ); + ctx.mOffset = offset; + const_cast(s).serial_process(RsGenericSerializer::SERIALIZE, + ctx); + return true; +} + +template<> bool RsTypeSerializer::deserialize( const uint8_t data[], + uint32_t size, uint32_t& offset, + RsItem& s ) +{ + RsGenericSerializer::SerializeContext ctx( + const_cast(data), size, + RsGenericSerializer::FORMAT_BINARY, + RsGenericSerializer::SERIALIZATION_FLAG_NONE ); + ctx.mOffset = offset; + const_cast(s).serial_process(RsGenericSerializer::DESERIALIZE, + ctx); + return true; +} + +template<> void RsTypeSerializer::print_data( const std::string& n, + const RsItem& s ) +{ + RsGenericSerializer::SerializeContext ctx( + NULL, 0, + RsGenericSerializer::FORMAT_BINARY, + RsGenericSerializer::SERIALIZATION_FLAG_NONE ); + const_cast(s).serial_process(RsGenericSerializer::PRINT, + ctx); +} diff --git a/libretroshare/src/serialiser/rstypeserializer.h b/libretroshare/src/serialiser/rstypeserializer.h index 333f1a364..ffc84e72b 100644 --- a/libretroshare/src/serialiser/rstypeserializer.h +++ b/libretroshare/src/serialiser/rstypeserializer.h @@ -33,409 +33,522 @@ #include "serialiser/rsserializer.h" +/** @def RS_REGISTER_SERIAL_MEMBER(I) + * Use this macro to register the members of `YourItem` for serial processing + * inside `YourItem::serial_process(j, ctx)` + * + * Inspired by http://stackoverflow.com/a/39345864 + */ +#define RS_REGISTER_SERIAL_MEMBER(I) \ + do { RsTypeSerializer::serial_process(j, ctx, I, #I); } while(0) -class RsTypeSerializer +/** @def RS_REGISTER_SERIAL_MEMBER_TYPED(I, T) + * This macro usage is similar to @see RS_REGISTER_SERIAL_MEMBER(I) but it + * permit to force serialization/deserialization type, it is expecially useful + * with enum class members ot RsTlvItem derivative members, be very careful with + * the type you pass, as reinterpret_cast on a reference is used that is + * expecially permissive so you can shot your feet if not carefull enough. + * + * If you are using this with an RsItem derivative (so passing RsItem as T) + * consider to register your item type with @see RS_REGISTER_ITEM_TYPE(T) in + * association with @see RS_REGISTER_SERIAL_MEMBER(I) that rely on template + * function generation, as in this particular case + * RS_REGISTER_SERIAL_MEMBER_TYPED(I, T) would cause the serial code rely on + * C++ dynamic dispatching that may have a noticeable impact on runtime + * performances. + */ +#define RS_REGISTER_SERIAL_MEMBER_TYPED(I, T) do {\ + RsTypeSerializer::serial_process(j, ctx, reinterpret_cast(I), #I);\ + } while(0) + +/** @def RS_REGISTER_ITEM_TYPE(T) + * Use this macro into `youritem.cc` only if you need to process members of + * subtypes of RsItem. + * + * The usage of this macro is strictly needed only in some cases, for example if + * you are registering for serialization a member of a container that contains + * items of subclasses of RsItem like * `std::map` + * + * @code{.cpp} +struct PrivateOugoingMapItem : RsChatItem { - public: - // This type should be used to pass a parameter to drive the serialisation if needed. + PrivateOugoingMapItem() : RsChatItem(RS_PKT_SUBTYPE_OUTGOING_MAP) {} - struct TlvMemBlock_proxy: public std::pair - { - TlvMemBlock_proxy(void *& p,uint32_t& s) : std::pair(p,s) {} - TlvMemBlock_proxy(uint8_t*& p,uint32_t& s) : std::pair(*(void**)&p,s) {} - }; + void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ); - //=================================================================================================// - // Generic types // - //=================================================================================================// - - template - static void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx,T& member,const std::string& member_name) - { - switch(j) - { - case RsGenericSerializer::SIZE_ESTIMATE: ctx.mOffset += serial_size(member) ; - break ; - - case RsGenericSerializer::DESERIALIZE: ctx.mOk = ctx.mOk && deserialize(ctx.mData,ctx.mSize,ctx.mOffset,member) ; - break ; - - case RsGenericSerializer::SERIALIZE: ctx.mOk = ctx.mOk && serialize(ctx.mData,ctx.mSize,ctx.mOffset,member) ; - break ; - - case RsGenericSerializer::PRINT: - print_data(member_name,member); - break; - default: - ctx.mOk = false ; - throw std::runtime_error("Unknown serial job") ; - } - } - - //=================================================================================================// - // Generic types + type_id // - //=================================================================================================// - - template - static void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx,uint16_t type_id,T& member,const std::string& member_name) - { - switch(j) - { - case RsGenericSerializer::SIZE_ESTIMATE: ctx.mOffset += serial_size(type_id,member) ; - break ; - - case RsGenericSerializer::DESERIALIZE: ctx.mOk = ctx.mOk && deserialize(ctx.mData,ctx.mSize,ctx.mOffset,type_id,member) ; - break ; - - case RsGenericSerializer::SERIALIZE: ctx.mOk = ctx.mOk && serialize(ctx.mData,ctx.mSize,ctx.mOffset,type_id,member) ; - break ; - - case RsGenericSerializer::PRINT: - print_data(member_name,type_id,member); - break; - default: - ctx.mOk = false ; - throw std::runtime_error("Unknown serial job") ; - } - } - //=================================================================================================// - // std::map // - //=================================================================================================// - - template - static void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx,std::map& v,const std::string& member_name) - { - switch(j) - { - case RsGenericSerializer::SIZE_ESTIMATE: - { - ctx.mOffset += 4 ; - for(typename std::map::iterator it(v.begin());it!=v.end();++it) - { - serial_process(j,ctx,const_cast(it->first),"map::*it->first") ; - serial_process(j,ctx,const_cast(it->second),"map::*it->second") ; - } - } - break ; - - case RsGenericSerializer::DESERIALIZE: - { - uint32_t n=0 ; - serial_process(j,ctx,n,"temporary size"); - - for(uint32_t i=0;ifirst") ; - serial_process(j,ctx,u,"map::*it->second") ; - - v[t] = u ; - } - } - break ; - - case RsGenericSerializer::SERIALIZE: - { - uint32_t n=v.size(); - serial_process(j,ctx,n,"temporary size"); - - for(typename std::map::iterator it(v.begin());it!=v.end();++it) - { - serial_process(j,ctx,const_cast(it->first),"map::*it->first") ; - serial_process(j,ctx,const_cast(it->second),"map::*it->second") ; - } - } - break ; - - case RsGenericSerializer::PRINT: - { - if(v.empty()) - std::cerr << " Empty map \"" << member_name << "\"" << std::endl; - else - std::cerr << " std::map of " << v.size() << " elements: \"" << member_name << "\"" << std::endl; - - for(typename std::map::iterator it(v.begin());it!=v.end();++it) - { - std::cerr << " " ; - - serial_process(j,ctx,const_cast(it->first),"map::*it->first") ; - serial_process(j,ctx,const_cast(it->second),"map::*it->second") ; - } - } - break; - default: - break; - } - } - - //=================================================================================================// - // std::vector // - //=================================================================================================// - - template - static void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx,std::vector& v,const std::string& member_name) - { - switch(j) - { - case RsGenericSerializer::SIZE_ESTIMATE: - { - ctx.mOffset += 4 ; - for(uint32_t i=0;i // - //=================================================================================================// - - template - static void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx,std::set& v,const std::string& member_name) - { - switch(j) - { - case RsGenericSerializer::SIZE_ESTIMATE: - { - ctx.mOffset += 4 ; - for(typename std::set::iterator it(v.begin());it!=v.end();++it) - serial_process(j,ctx,const_cast(*it) ,member_name) ; // the const cast here is a hack to avoid serial_process to instantiate serialise(const T&) - } - break ; - - case RsGenericSerializer::DESERIALIZE: - { uint32_t n=0 ; - serial_process(j,ctx,n,"temporary size") ; - - for(uint32_t i=0;i(j,ctx,tmp,member_name) ; - v.insert(tmp); - } - } - break ; - - case RsGenericSerializer::SERIALIZE: - { - uint32_t n=v.size(); - serial_process(j,ctx,n,"temporary size") ; - for(typename std::set::iterator it(v.begin());it!=v.end();++it) - serial_process(j,ctx,const_cast(*it) ,member_name) ; // the const cast here is a hack to avoid serial_process to instantiate serialise(const T&) - } - break ; - - case RsGenericSerializer::PRINT: - { - if(v.empty()) - std::cerr << " Empty set"<< std::endl; - else - std::cerr << " Set of " << v.size() << " elements:" << std::endl; - } - break; - default: - break; - } - } - - - //=================================================================================================// - // std::list // - //=================================================================================================// - - template - static void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx,std::list& v,const std::string& member_name) - { - switch(j) - { - case RsGenericSerializer::SIZE_ESTIMATE: - { - ctx.mOffset += 4 ; - for(typename std::list::iterator it(v.begin());it!=v.end();++it) - serial_process(j,ctx,*it ,member_name) ; - } - break ; - - case RsGenericSerializer::DESERIALIZE: - { uint32_t n=0 ; - serial_process(j,ctx,n,"temporary size") ; - - for(uint32_t i=0;i(j,ctx,tmp,member_name) ; - v.push_back(tmp); - } - } - break ; - - case RsGenericSerializer::SERIALIZE: - { - uint32_t n=v.size(); - serial_process(j,ctx,n,"temporary size") ; - for(typename std::list::iterator it(v.begin());it!=v.end();++it) - serial_process(j,ctx,*it ,member_name) ; - } - break ; - - case RsGenericSerializer::PRINT: - { - if(v.empty()) - std::cerr << " Empty list"<< std::endl; - else - std::cerr << " List of " << v.size() << " elements:" << std::endl; - } - break; - default: - break; - } - } - - //=================================================================================================// - // t_RsFlags32<> types // - //=================================================================================================// - - template - static void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx,t_RsFlags32& v,const std::string& member_name) - { - switch(j) - { - case RsGenericSerializer::SIZE_ESTIMATE: ctx.mOffset += 4 ; - break ; - - case RsGenericSerializer::DESERIALIZE: - { - uint32_t n=0 ; - deserialize(ctx.mData,ctx.mSize,ctx.mOffset,n) ; - v = t_RsFlags32(n) ; - } - break ; - - case RsGenericSerializer::SERIALIZE: - { - uint32_t n=v.toUInt32() ; - serialize(ctx.mData,ctx.mSize,ctx.mOffset,n) ; - } - break ; - - case RsGenericSerializer::PRINT: - std::cerr << " Flags of type " << std::hex << N << " : " << v.toUInt32() << std::endl; - break ; - } - - } - - protected: - template static bool serialize (uint8_t data[], uint32_t size, uint32_t &offset, const T& member); - template static bool deserialize(const uint8_t data[], uint32_t size, uint32_t &offset, T& member); - template static uint32_t serial_size(const T& /* member */); - template static void print_data(const std::string& name,const T& /* member */); - - template static bool serialize (uint8_t data[], uint32_t size, uint32_t &offset, uint16_t type_id,const T& member); - template static bool deserialize(const uint8_t data[], uint32_t size, uint32_t &offset,uint16_t type_id, T& member); - template static uint32_t serial_size(uint16_t type_id,const T& /* member */); - template static void print_data(const std::string& name,uint16_t type_id,const T& /* member */); - - template static bool serialize (uint8_t data[], uint32_t size, uint32_t &offset, const t_RsGenericIdType& member); - template static bool deserialize(const uint8_t data[], uint32_t size, uint32_t &offset, t_RsGenericIdType& member); - template static uint32_t serial_size(const t_RsGenericIdType& /* member */); - template static void print_data(const std::string& name,const t_RsGenericIdType& /* member */); - - template static bool serialize (uint8_t data[], uint32_t size, uint32_t &offset, const t_RsTlvList& member); - template static bool deserialize(const uint8_t data[], uint32_t size, uint32_t &offset, t_RsTlvList& member); - template static uint32_t serial_size(const t_RsTlvList& /* member */); - template static void print_data(const std::string& name,const t_RsTlvList& /* member */); + std::map store; }; -//=================================================================================================// -// t_RsGenericId<> // -//=================================================================================================// +RS_REGISTER_ITEM_TYPE(RsChatMsgItem) + +void PrivateOugoingMapItem::serial_process( + RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ) +{ + // store is of type + RS_REGISTER_SERIAL_MEMBER(store); +} + * @endcode + * + * If you use this macro with a lot of different item types this can cause the + * generated binary grow in size, consider the usage of + * @see RS_REGISTER_SERIAL_MEMBER_TYPED(I, T) passing RsItem as type in that + * case. + */ +#define RS_REGISTER_ITEM_TYPE(T) template<> \ + void RsTypeSerializer::serial_process( \ + RsGenericSerializer::SerializeJob j,\ + RsGenericSerializer::SerializeContext& ctx, T& item,\ + const std::string& /*name*/) { item.serial_process(j, ctx); } + +struct RsTypeSerializer +{ + /** This type should be used to pass a parameter to drive the serialisation + * if needed */ + struct TlvMemBlock_proxy: public std::pair + { + TlvMemBlock_proxy(void*& p, uint32_t& s) : + std::pair(p,s) {} + TlvMemBlock_proxy(uint8_t*& p,uint32_t& s) : + std::pair(*(void**)&p,s) {} + }; + + /// Generic types + template + static void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx, + T& member,const std::string& member_name) + { + switch(j) + { + case RsGenericSerializer::SIZE_ESTIMATE: + ctx.mOffset += serial_size(member); + break; + case RsGenericSerializer::DESERIALIZE: + ctx.mOk = ctx.mOk && + deserialize(ctx.mData,ctx.mSize,ctx.mOffset,member); + break; + case RsGenericSerializer::SERIALIZE: + ctx.mOk = ctx.mOk && + serialize(ctx.mData,ctx.mSize,ctx.mOffset,member); + break; + case RsGenericSerializer::PRINT: + print_data(member_name,member); + break; + default: + ctx.mOk = false; + throw std::runtime_error("Unknown serial job"); + } + } + + /// Generic types + type_id + template + static void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx, + uint16_t type_id, T& member, + const std::string& member_name ) + { + switch(j) + { + case RsGenericSerializer::SIZE_ESTIMATE: + ctx.mOffset += serial_size(type_id,member); + break; + case RsGenericSerializer::DESERIALIZE: + ctx.mOk = ctx.mOk && + deserialize(ctx.mData,ctx.mSize,ctx.mOffset,type_id,member); + break; + case RsGenericSerializer::SERIALIZE: + ctx.mOk = ctx.mOk && + serialize(ctx.mData,ctx.mSize,ctx.mOffset,type_id,member); + break; + case RsGenericSerializer::PRINT: + print_data(member_name,type_id,member); + break; + default: + ctx.mOk = false; + throw std::runtime_error("Unknown serial job"); + } + } + + /// std::map + template + static void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx, + std::map& v, + const std::string& member_name ) + { + switch(j) + { + case RsGenericSerializer::SIZE_ESTIMATE: + { + ctx.mOffset += 4; + for(typename std::map::iterator it(v.begin());it!=v.end();++it) + { + serial_process( j, ctx, const_cast(it->first), + "map::*it->first" ); + serial_process( j,ctx,const_cast(it->second), + "map::*it->second" ); + } + break; + } + case RsGenericSerializer::DESERIALIZE: + { + uint32_t n=0; + serial_process(j,ctx,n,"temporary size"); + + for(uint32_t i=0; ifirst"); + serial_process(j, ctx, u, "map::*it->second"); + v[t] = u; + } + break; + } + case RsGenericSerializer::SERIALIZE: + { + uint32_t n=v.size(); + serial_process(j,ctx,n,"temporary size"); + + for(typename std::map::iterator it(v.begin());it!=v.end();++it) + { + serial_process( j, ctx, const_cast(it->first), + "map::*it->first" ); + serial_process( j, ctx, const_cast(it->second), + "map::*it->second" ); + } + break; + } + case RsGenericSerializer::PRINT: + { + if(v.empty()) + std::cerr << " Empty map \"" << member_name << "\"" + << std::endl; + else + std::cerr << " std::map of " << v.size() << " elements: \"" + << member_name << "\"" << std::endl; + + for(typename std::map::iterator it(v.begin());it!=v.end();++it) + { + std::cerr << " "; + + serial_process( j, ctx,const_cast(it->first), + "map::*it->first" ); + serial_process( j, ctx, const_cast(it->second), + "map::*it->second" ); + } + break; + } + default: break; + } + } + + /// std::vector + template + static void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx, + std::vector& v, + const std::string& member_name ) + { + switch(j) + { + case RsGenericSerializer::SIZE_ESTIMATE: + { + ctx.mOffset += 4; + for(uint32_t i=0;i + template + static void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx, + std::set& v, const std::string& member_name ) + { + switch(j) + { + case RsGenericSerializer::SIZE_ESTIMATE: + { + ctx.mOffset += 4; + for(typename std::set::iterator it(v.begin());it!=v.end();++it) + // the const cast here is a hack to avoid serial_process to + // instantiate serialise(const T&) + serial_process(j,ctx,const_cast(*it) ,member_name); + break; + } + case RsGenericSerializer::DESERIALIZE: + { + uint32_t n=0; + serial_process(j,ctx,n,"temporary size"); + for(uint32_t i=0; i(j,ctx,tmp,member_name); + v.insert(tmp); + } + break; + } + case RsGenericSerializer::SERIALIZE: + { + uint32_t n=v.size(); + serial_process(j,ctx,n,"temporary size"); + for(typename std::set::iterator it(v.begin());it!=v.end();++it) + // the const cast here is a hack to avoid serial_process to + // instantiate serialise(const T&) + serial_process(j,ctx,const_cast(*it) ,member_name); + break; + } + case RsGenericSerializer::PRINT: + { + if(v.empty()) std::cerr << " Empty set"<< std::endl; + else std::cerr << " Set of " << v.size() << " elements:" + << std::endl; + break; + } + default: break; + } + } + + /// std::list + template + static void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx, + std::list& v, + const std::string& member_name ) + { + switch(j) + { + case RsGenericSerializer::SIZE_ESTIMATE: + { + ctx.mOffset += 4; + for(typename std::list::iterator it(v.begin());it!=v.end();++it) + serial_process(j,ctx,*it ,member_name); + break; + } + case RsGenericSerializer::DESERIALIZE: + { + uint32_t n=0; + serial_process(j,ctx,n,"temporary size"); + for(uint32_t i=0;i(j,ctx,tmp,member_name); + v.push_back(tmp); + } + break; + } + case RsGenericSerializer::SERIALIZE: + { + uint32_t n=v.size(); + serial_process(j,ctx,n,"temporary size"); + for(typename std::list::iterator it(v.begin());it!=v.end();++it) + serial_process(j,ctx,*it ,member_name); + break; + } + case RsGenericSerializer::PRINT: + { + if(v.empty()) std::cerr << " Empty list"<< std::endl; + else std::cerr << " List of " << v.size() << " elements:" + << std::endl; + break; + } + default: break; + } + } + + /// t_RsFlags32<> types + template + static void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx, + t_RsFlags32& v, + const std::string& /*member_name*/) + { + switch(j) + { + case RsGenericSerializer::SIZE_ESTIMATE: ctx.mOffset += 4; break; + case RsGenericSerializer::DESERIALIZE: + { + uint32_t n=0; + deserialize(ctx.mData,ctx.mSize,ctx.mOffset,n); + v = t_RsFlags32(n); + break; + } + case RsGenericSerializer::SERIALIZE: + { + uint32_t n=v.toUInt32(); + serialize(ctx.mData,ctx.mSize,ctx.mOffset,n); + break; + } + case RsGenericSerializer::PRINT: + std::cerr << " Flags of type " << std::hex << N << " : " + << v.toUInt32() << std::endl; + break; + } + } + +/** TODO + * Serialization format is inside context, but context is not passed to + * following functions, that need to know the format to do the job, actually + * RsGenericSerializer::FORMAT_BINARY is assumed in all of them!! + */ + +protected: + template static bool serialize( + uint8_t data[], uint32_t size, uint32_t &offset, const T& member ); + + template static bool deserialize( + const uint8_t data[], uint32_t size, uint32_t &offset, T& member); + + template static uint32_t serial_size(const T& member); + + template static void print_data( + const std::string& name, const T& member); + + + template static bool serialize( + uint8_t data[], uint32_t size, uint32_t &offset, uint16_t type_id, + const T& member ); + template static bool deserialize( + const uint8_t data[], uint32_t size, uint32_t &offset, + uint16_t type_id, T& member ); + template static uint32_t serial_size( + uint16_t type_id,const T& member ); + template static void print_data( + const std::string& name,uint16_t type_id,const T& member ); + + + template + static bool serialize( + uint8_t data[], uint32_t size, uint32_t &offset, + const t_RsGenericIdType& member ); + + template + static bool deserialize( + const uint8_t data[], uint32_t size, uint32_t &offset, + t_RsGenericIdType& member ); + + template + static uint32_t serial_size( + const t_RsGenericIdType& member ); + + template + static void print_data( + const std::string& name, + const t_RsGenericIdType& member ); + + + template + static bool serialize( + uint8_t data[], uint32_t size, uint32_t &offset, + const t_RsTlvList& member ); + + template + static bool deserialize( + const uint8_t data[], uint32_t size, uint32_t &offset, + t_RsTlvList& member ); + + template + static uint32_t serial_size(const t_RsTlvList& member); + + template + static void print_data( + const std::string& name, + const t_RsTlvList& member); +}; + + + +// t_RsGenericId<> +template +bool RsTypeSerializer::serialize ( + uint8_t data[], uint32_t size, uint32_t &offset, + const t_RsGenericIdType& member ) +{ return (*const_cast *>(&member)).serialise(data,size,offset); } template -bool RsTypeSerializer::serialize (uint8_t data[], uint32_t size, uint32_t &offset, const t_RsGenericIdType& member) -{ - return (*const_cast *>(&member)).serialise(data,size,offset) ; -} +bool RsTypeSerializer::deserialize( + const uint8_t data[], uint32_t size, uint32_t &offset, + t_RsGenericIdType& member ) +{ return member.deserialise(data,size,offset); } template -bool RsTypeSerializer::deserialize(const uint8_t data[], uint32_t size, uint32_t &offset, t_RsGenericIdType& member) -{ - return member.deserialise(data,size,offset) ; -} +uint32_t RsTypeSerializer::serial_size( + const t_RsGenericIdType& member ) +{ return member.serial_size(); } template -uint32_t RsTypeSerializer::serial_size(const t_RsGenericIdType& member) +void RsTypeSerializer::print_data( + const std::string& /*name*/, + const t_RsGenericIdType& member ) { - return member.serial_size(); + std::cerr << " [RsGenericId<" << std::hex << UNIQUE_IDENTIFIER << ">] : " + << member << std::endl; } -template -void RsTypeSerializer::print_data(const std::string& /* name */,const t_RsGenericIdType& member) -{ - std::cerr << " [RsGenericId<" << std::hex << UNIQUE_IDENTIFIER << ">] : " << member << std::endl; -} - -//=================================================================================================// -// t_RsTlvList<> // -//=================================================================================================// +// t_RsTlvList<> template -bool RsTypeSerializer::serialize (uint8_t data[], uint32_t size, uint32_t &offset, const t_RsTlvList& member) +bool RsTypeSerializer::serialize( + uint8_t data[], uint32_t size, uint32_t &offset, + const t_RsTlvList& member ) { - return (*const_cast *>(&member)).SetTlv(data,size,&offset) ; + return (*const_cast *>(&member)).SetTlv(data,size,&offset); } template -bool RsTypeSerializer::deserialize(const uint8_t data[], uint32_t size, uint32_t &offset, t_RsTlvList& member) +bool RsTypeSerializer::deserialize( + const uint8_t data[], uint32_t size, uint32_t &offset, + t_RsTlvList& member ) { - return member.GetTlv(const_cast(data),size,&offset) ; + return member.GetTlv(const_cast(data),size,&offset); } template -uint32_t RsTypeSerializer::serial_size(const t_RsTlvList& member) -{ - return member.TlvSize(); -} +uint32_t RsTypeSerializer::serial_size( + const t_RsTlvList& member) +{ return member.TlvSize(); } template -void RsTypeSerializer::print_data(const std::string& /* name */,const t_RsTlvList& member) +void RsTypeSerializer::print_data( + const std::string& /*name*/, + const t_RsTlvList& member) { - std::cerr << " [t_RsTlvString<" << std::hex << TLV_TYPE << ">] : size=" << member.mList.size() << std::endl; + std::cerr << " [t_RsTlvString<" << std::hex << TLV_TYPE << ">] : size=" + << member.mList.size() << std::endl; } From 8e9b3c97d5b8fc6b8130ce092a33d11de82d1506 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Mon, 8 May 2017 12:03:42 +0200 Subject: [PATCH 33/35] Fix missing include --- libretroshare/src/rsitems/rsitem.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libretroshare/src/rsitems/rsitem.h b/libretroshare/src/rsitems/rsitem.h index 5698728a0..068f9ee83 100644 --- a/libretroshare/src/rsitems/rsitem.h +++ b/libretroshare/src/rsitems/rsitem.h @@ -1,5 +1,7 @@ #pragma once +#include // for typeid + #include "util/smallobject.h" #include "retroshare/rstypes.h" #include "serialiser/rsserializer.h" From 837fcd7989a46e5ebd4572053c7451ada70da2e2 Mon Sep 17 00:00:00 2001 From: defnax Date: Fri, 12 May 2017 18:29:39 +0200 Subject: [PATCH 34/35] Added Placeholder text for Password field, removed "Password:" label. --- retroshare-gui/src/gui/StartDialog.ui | 30 ++++++++++++--------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/retroshare-gui/src/gui/StartDialog.ui b/retroshare-gui/src/gui/StartDialog.ui index 572df161d..4665dfdc0 100644 --- a/retroshare-gui/src/gui/StartDialog.ui +++ b/retroshare-gui/src/gui/StartDialog.ui @@ -195,6 +195,13 @@ 9 + + + + Profile - Location: + + + @@ -217,7 +224,7 @@ - + @@ -236,28 +243,17 @@ - + QLineEdit::Password - - - - - - Password: + + Password - - - - Profile - Location: - - - - + Remember Password @@ -267,7 +263,7 @@ - + From 2f17a8010343e27b4f8595b4632e85ebacfd319f Mon Sep 17 00:00:00 2001 From: defnax Date: Fri, 12 May 2017 21:39:50 +0200 Subject: [PATCH 35/35] added missed icons --- retroshare-gui/src/gui/icons/stars/star0.png | Bin 0 -> 7190 bytes retroshare-gui/src/gui/icons/stars/star0.svg | 131 +++++++++ retroshare-gui/src/gui/icons/stars/star1.png | Bin 0 -> 6561 bytes retroshare-gui/src/gui/icons/stars/star1.svg | 157 +++++++++++ retroshare-gui/src/gui/icons/stars/star2.png | Bin 0 -> 6560 bytes retroshare-gui/src/gui/icons/stars/star2.svg | 184 +++++++++++++ retroshare-gui/src/gui/icons/stars/star3.png | Bin 0 -> 5710 bytes retroshare-gui/src/gui/icons/stars/star3.svg | 210 ++++++++++++++ retroshare-gui/src/gui/icons/stars/star4.png | Bin 0 -> 5668 bytes retroshare-gui/src/gui/icons/stars/star4.svg | 237 ++++++++++++++++ retroshare-gui/src/gui/icons/stars/star5.png | Bin 0 -> 5267 bytes retroshare-gui/src/gui/icons/stars/star5.svg | 271 +++++++++++++++++++ 12 files changed, 1190 insertions(+) create mode 100644 retroshare-gui/src/gui/icons/stars/star0.png create mode 100644 retroshare-gui/src/gui/icons/stars/star0.svg create mode 100644 retroshare-gui/src/gui/icons/stars/star1.png create mode 100644 retroshare-gui/src/gui/icons/stars/star1.svg create mode 100644 retroshare-gui/src/gui/icons/stars/star2.png create mode 100644 retroshare-gui/src/gui/icons/stars/star2.svg create mode 100644 retroshare-gui/src/gui/icons/stars/star3.png create mode 100644 retroshare-gui/src/gui/icons/stars/star3.svg create mode 100644 retroshare-gui/src/gui/icons/stars/star4.png create mode 100644 retroshare-gui/src/gui/icons/stars/star4.svg create mode 100644 retroshare-gui/src/gui/icons/stars/star5.png create mode 100644 retroshare-gui/src/gui/icons/stars/star5.svg diff --git a/retroshare-gui/src/gui/icons/stars/star0.png b/retroshare-gui/src/gui/icons/stars/star0.png new file mode 100644 index 0000000000000000000000000000000000000000..a7dc2a47717289971cbe73d73623a30466758c4b GIT binary patch literal 7190 zcmZvhbzBrr+{gE*qr0RLDQP^UOQln~IYPQy>J9{?6a}OO32BZH>Fzub1Oz-%q)YmU zd-y$nKCfqAuie@Cymsb0J2N}q{mwg1S6hXIkbw{Y01`FT7kU5yy1xZf@bT`iTPB(R zB{;s%)C}e)^scet|YVuYkb7KtX2@ zS6@3DuUCSeK91Q3G7JE~n4E{wM+XewOOLKG#9{YokIAnj7))GEANJ zlRY_mJ_EEOO|c4+0|B(OwEB#A7Zjz8T~-cm2%dm;^%v;Lr;t-6jf*bZsan#mn_+4f z8ygW`rb%2YOT*OfhZfzh!INvuO`q|F0569ZS<%t`_T)ALjeHuvg|Ho&6}}0z=|UH9 zM=u5V1##>nF0<;KO<4)Y`0@E=u>V)2wvZy45dNm%{(05hOi z9WBMj8nA79z?nIl8h>-JJlA|3Ffm!QX15d%Ga;n3xR;q`6Bbz(Ie3|U?I$*q&Z#lu z-!qL;6M0>Ak(1r)$fIr==q+V>=oaZ_SANxh)$|}XlPFy|ffZurrZEI0z}`$>RMoht z>%t8rVWeGY@$xs?lLU~MZb`N=W|00J)|!sRLo2%Z15-0^B-y0XH?@Z;WPdZyt2GDmZPL?mSXihjk{M~#eawgQ~dzs zWIk0S%X`LTN|kEwXfkcJiM-wAP%Jp4UNb%bnVy=)yNMHP7!(Q1bl_>A@k3-M<8kr| zSQbn*vvs8M`GjC@!X2o;a<{Igkt=(k=?QVC6})7Pj8gFle*BT!URQ=hsJ#A)_L~ zdk+4|Q$Ed>?uVbA0ObUt@#i_Y~7Y(c@9*u}bOT_Fg zHGU)MA1F&R*a|E5uY-K;DMknHsV5vCuvVv^&Cf>!mh^pJIjE@OHj=mFc|XlpZke#} zvKgnAD#our0-}DTtnr}hHb#`a(-+m;lF059Mq#|g@#fnao-oSY=`ro4l~WeK40`MC4#)e|6-T!>Av@a7f9 zDY4>3ciVuj!{~+FdN#k|w(u(^_;Wdb<;mc+H_nN3&f93~h#Fs~S}n4$VL2};gj?P4 zNoOei%H?z_ebSFlyLUJP9r^v|s_PrcJEIn{7K8eG7xYfzz7I1!8q8o9+n=O5FOqx9#f)itN zfwL8*wHvK3$8vFpfq^_>9s@7uG_0bfly z!U{ai#%$|bQ8Wv%FJE@&$>ItJS}{^)bw9|O*Ej+1Zr;`f^u}K9+;YIk;Q8XI?j{bA zET2k(y888Y@#Hi%7+X-E7)=M zd7*uk^D%|Oyk4KuR#vhhLyvfiMm6jGnCIjaiFhu|(D;M}?wTALPl)d>l3l3LNORi1 z_qBX2gO}%EUa8zfl;{yXj7=X$mN=yTtEHY9cJdShP2qlIDXvVB%82mI8~t!qjX4ZA zApAzx+82Po#<~8D!O4Hy&y>fdrC)F^s`qt-f5z0PSpAjuVQw z>@WApA61EKO!m;gt#a0?*kgM%%`OeZ0k5#L!0uDG`16-BX2f3*%dA zg$n(8GGVoS5fPzM_347F_Ghsz4lM=mGnHCaazDPGRc!akvviiSOV`2ebE*(5lWW!5 z9o2Y#_@v(Nw)`a6)%85GhR50U8GLmsHck>`_&7ls^=+@bT~x?LsKT~8^Alp}hp-K) zLSn#Ey1<*_H@5lBKw@{vDm#A(=kA1KiMQqWJHU!HI+cwm_l@NShR--9K3VP*GKg7N z-CL1P2lzQ%Qz8R~795@WzkU4A-~ra^*O#Zb_~!^@JZvaF4)?FT+-}C~9qaX;`iTr& zC4~yZXx4H!xY>FQeTSpv33&Y&YArawYZKbv<+~gZ7&iM=ub|_-yDkv9Bu^I;RaOse zNkCXMUfqn!&U|B=#_qf~LU`BV6Z-VOb# zertPu^K5qZH(t*u#~v6kK>d}RGQ3l8)*Rzw?zkGttl?D%pBoU2k4}R^2FTjPe_nzB zjoD66k4oVdU;62!*wyFVEPb(&gT-7~^>uK@U0CTcHeeQM4ls$sdWE-s*y4jYiIJ)J6!sA$JlvL=c}}Q z+`EnFA-s2UWGy@E&o7oo<^Lov})6evFaGAlj6I&TWwOEwm!t}(|gcs9H< z4Kx4}wu$v*)pG%aQ8)H8@w){-i0u}EJ>UfUg)0?Fnr$a=M2ojhSNqYgQeBA`yDrN> zW-3E(ukw8(+mSpYU)<~t+bsx?1`>lZ4Zj;}{X(D!va!f3GG@<%?mcCWyB;&{mZ7jX z+>4T&ft*Tv(y&uYn(Ey}cr|s+IB42U*a4J*y}~FQ$LnNk^SOFwRcNb*(_ek8wqsi$ z>F0cXm$7DfD=3`2<%j@M6_J+Y!RzQ%s`aD`%}>6Jvm%$`;N!J`T6{jQ;Rz{|)-i&G z>E|8>ZV0zmOa;J~!CqMW5QW&BB2LCz=iNWwvCiuao{>9X%P?Y1V68ueJ3MNjLHZfW zQqLAS`|6*@Mj{+ZTb{9IYjx8nYO%=?>tf?b5vUYJ&=z$@#3WVL+p&dkL9(!OW;8EJ z;W&d-R5I6Xbh4u9YU(?ws>X$1tK{YRo!axn%UA$A4h0hU63`&V)_4K2Jb&x75G-%9 zuB@3&LhFE?fx99KEJv!1`2M_|H?!WpsD_j=&~ZWVRhfG0&tdY9d8@eSz}3CUBOzMt z*Z8aZu1Za2x!|qN2fGF#^9aO0a9TtZu#EBV9Bp~ThwZy zh>uNFW;mP~xR5MSG@Ax2>;haKI)y-Y`kG=%CnLbzCJ@+t5u7T=#!sY$S%MziY zS2ut{{7`m<$So@|kWB+j`b zk&dG5Qn1QIdaeD=v2acZtEtzd@`Gv zv6gC|MVMkuE#pw8eYojJK7`SaxBPTNi|`|dYXA1U=O*kXcy1-+7Ah;S;1vY9^|2fe z1MY-~*L7loYSs(#n&S3w3OOdO_SgMw5RXVP-W)eApW|V@$>yk+1y4$7Am{L zgZZY0BJqk7dgu43%U{eI*skXIarx$MN(`**dIOMqTbXSLnKCP^seZu`2~N4FyxLQ} z{)5hP0Xh{6j$u=#XF6AfV&MQjEh<1sBJirakE~y`>ughToj$_IitkIuMx$CH<`(hq zZF&+KUxddOud)6RjTndLXv7j<&WCbh{!vv2}ffeM=hY zqN?MG+F^y)lE&=5QIlDaTz52W$uO5RYLDoV{`=OaTEh>kOAPMH2s>>zhxy@CbGDimt$sUJI|zRFu5BRS+swIp)ScPbZ9#$Nh$ zkP8CN=h+eXP_ZT5IF(=@mmAzFS4U|U7`_MvQ$i<)H#*pPK86MG9(*$osg_nd5wV+o z7Uw!uE^vF8?)~d%L9s>DM#YSPpAptb#bIg;?mg=4mto8L^5?bxvtIStxhHg@KUv zl-6&hhf3`ngnsXELW+Jk$+-KCQxOzm$sK*>pI)i>u=P9V-!Z}BpkO)b_#{kJytHUE zDl%X8L^GmLYrRmA#a4@})G%i4BM1^qy` z13|r*b0>)RyI5qOufejWcB-tu!*^X8KoY>DIG_qt#dt{f`-|!PyRN`fX%CLHQj2d8*NR$N9g4-S87+y7 zDWHGkcORD&PM)UFkNpwF^V)M9)$zF($j_osjsaIG1d?oe@eK@fH#%QBzT@Hk^Cp+i z%9shv-RO!p1D3tY)a;99K|>!S$84| z+hfr(&|q>A^i#Y*o6oH8=RXY)T*2I2CY@GJK#%qSO{|C`e__g}7r!>96(#vZ*gg1T z)m_D*UaBuJSZp(K-}8D*@FE&}Yeum8{zARpE;VUeK5FLm-cZ@B0=^a+13{cPXenZ( znt{}m6pllYs(J-`eyq~3OE$QlvZ{x$EdEr*JDT$$XWV9M2G)-pY#bc$D1g2f#Flx? zt?`Zjt&Jd88A>gwjYXiZTv_)WU0B_r0C8PdMv>sEER}bJ6HEk==m%hYH~y_nvLGKJ>e3zQ*Hk@|e%z2q=xOUb`)e+JNzmK*m8XL zUtvoc@6NY-&NzY_!tg4&TMKE3%$7lxW2PU9!uup1mb8E}3r_62WW=5lGZ z?poM9+Ko3~_$Eg;wzGKUmWxTs!`>|pR!y(K+xNJ^!?OM9DsvmiE?we=F9(&euwvQGBN_EjtdQLv6+8?Z$^GoL!QdHovx;drR!8yFP(yr0jlrj~m}H z&w{jS!gBOPhw))JzcEwkw*y*u`$ZeB$3FbNXudw4E zll#A|OK08ZYkSR}BFp}vhdjFDCOhqP)3SQ=5)(Q!-MITuLB~WR@G-X(USIV37Qmq8 zOJs7i_wN&;t^#S=nBAG;+bcQRDgMFN5Qe~f7e__xpTzz0s{J-tjC&&@BEM=HR``Z} z>z0$CA4jQnBIsL5kpn{TZ$>VvM5@9em=7j3Etuytau_VfKM+ZvBSZNq&AVNq-$_LX z>XS^~O^572Lu*#jIQbJ9Q)q|Zjbqf%ZPul42!{(0m!GAaA7JVa$C!a+8H67XMDNbV(gTUl3 zf72cA@FFrRh;kthZKERgDumKyHR|v8Nq1zz4#)9!H$U@w`&m@uPJ!3fILEdg44DS- znD`Caa(Vx1XV(k}tl2u>xW%>J9lr4Ry`7pQFaW(-v%uKNxj7VRB3}c~$xlI5MH`#$ zkt~n(n4er+Cmd!{QJqj8nmOC*-{#*SHgzOZ2PEBm#r=({1m=cCJWK;3Sv&;YZ|8c0 zHIW2#OTVY{zTH#+%I^42!&VF;0((Jfa+ZRd7BjQves6~}u?x8yuQv)!Z(EDEBTLwI zZ)9Isd{eF?;9;3vB{-1Dm~NdRDGh)PXF2rC&be9NlwJ#YgzUko_jwHWKdA((A7+-t zMGqI7_deW;Pu^W_TV_VrBoF`C6@Zlrb8Qqgm+`#2`z{A_UKCoONT7WoL&OlAa9}nR z$v2bA$N5xXMc`D{*CIJv@JCUkvS+^z-B(!9_@(gu7tqsVyCeLHg~Z{W^j!TPY*JIx z1g~X+NB83<{y(Gz)D^{4U~^w=gMdgl$H>*j#=Cn`5H7se;eStcI+cTx6hySIDU9zy z6HJM`f&7WSd7}l-79%6pbk>iE0FH95h5Hl#@L`$qW^WIc2FR3${?GNWe& zuZ$l4CV)PGZx2nLVBbTcfvA}7S9hqfUluR-f + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/retroshare-gui/src/gui/icons/stars/star1.png b/retroshare-gui/src/gui/icons/stars/star1.png new file mode 100644 index 0000000000000000000000000000000000000000..875eecbb635639fbeee8b29467f79c1713b20971 GIT binary patch literal 6561 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 F`ai|1o>2e* literal 0 HcmV?d00001 diff --git a/retroshare-gui/src/gui/icons/stars/star1.svg b/retroshare-gui/src/gui/icons/stars/star1.svg new file mode 100644 index 000000000..f30284678 --- /dev/null +++ b/retroshare-gui/src/gui/icons/stars/star1.svg @@ -0,0 +1,157 @@ + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/retroshare-gui/src/gui/icons/stars/star2.png b/retroshare-gui/src/gui/icons/stars/star2.png new file mode 100644 index 0000000000000000000000000000000000000000..507e728987392962ee2035d025c36f68e52a46ec GIT binary patch literal 6560 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 AZvX%Q literal 0 HcmV?d00001 diff --git a/retroshare-gui/src/gui/icons/stars/star2.svg b/retroshare-gui/src/gui/icons/stars/star2.svg new file mode 100644 index 000000000..0b68c74a6 --- /dev/null +++ b/retroshare-gui/src/gui/icons/stars/star2.svg @@ -0,0 +1,184 @@ + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/retroshare-gui/src/gui/icons/stars/star3.png b/retroshare-gui/src/gui/icons/stars/star3.png new file mode 100644 index 0000000000000000000000000000000000000000..654ae5319dfacc261e8070d7e239d5332a1fb4bb GIT binary patch literal 5710 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 + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/retroshare-gui/src/gui/icons/stars/star4.png b/retroshare-gui/src/gui/icons/stars/star4.png new file mode 100644 index 0000000000000000000000000000000000000000..0a6769f139ece375da317b3ddc1c0616637fd7d6 GIT binary patch literal 5668 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 W{q>cB%VRXr1=LkuC|4`OBmM_qSiTYf literal 0 HcmV?d00001 diff --git a/retroshare-gui/src/gui/icons/stars/star4.svg b/retroshare-gui/src/gui/icons/stars/star4.svg new file mode 100644 index 000000000..af9ca8469 --- /dev/null +++ b/retroshare-gui/src/gui/icons/stars/star4.svg @@ -0,0 +1,237 @@ + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/retroshare-gui/src/gui/icons/stars/star5.png b/retroshare-gui/src/gui/icons/stars/star5.png new file mode 100644 index 0000000000000000000000000000000000000000..dd6f15dd92052f8f3a0eef9b4f9ed677bdc03369 GIT binary patch literal 5267 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 + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file