diff --git a/libretroshare/src/gxs/rsgxsnetservice.cc b/libretroshare/src/gxs/rsgxsnetservice.cc index 5fc4427ad..914b6ce4e 100644 --- a/libretroshare/src/gxs/rsgxsnetservice.cc +++ b/libretroshare/src/gxs/rsgxsnetservice.cc @@ -359,7 +359,7 @@ RsGxsNetService::RsGxsNetService(uint16_t servType, RsGeneralDataService *gds, RsNxsNetMgr *netMgr, RsNxsObserver *nxsObs, const RsServiceInfo serviceInfo, RsGixsReputation* reputations, RsGcxs* circles, RsGixs *gixs, - PgpAuxUtils *pgpUtils, bool grpAutoSync, bool msgAutoSync, uint32_t default_store_period, uint32_t default_sync_period) + PgpAuxUtils *pgpUtils, bool grpAutoSync, bool msgAutoSync, bool distSync, uint32_t default_store_period, uint32_t default_sync_period) : p3ThreadedService(), p3Config(), mTransactionN(0), mObserver(nxsObs), mDataStore(gds), mServType(servType), mTransactionTimeOut(TRANSAC_TIMEOUT), @@ -368,7 +368,7 @@ RsGxsNetService::RsGxsNetService(uint16_t servType, RsGeneralDataService *gds, mLastCleanRejectedMessages(0), mSYNC_PERIOD(SYNC_PERIOD), mCircles(circles), mGixs(gixs), mReputations(reputations), mPgpUtils(pgpUtils), - mGrpAutoSync(grpAutoSync), mAllowMsgSync(msgAutoSync), + mGrpAutoSync(grpAutoSync), mAllowMsgSync(msgAutoSync),mAllowDistSync(distSync), mServiceInfo(serviceInfo), mDefaultMsgStorePeriod(default_store_period), mDefaultMsgSyncPeriod(default_sync_period) { diff --git a/libretroshare/src/gxs/rsgxsnetservice.h b/libretroshare/src/gxs/rsgxsnetservice.h index 00ba07953..49d44dab2 100644 --- a/libretroshare/src/gxs/rsgxsnetservice.h +++ b/libretroshare/src/gxs/rsgxsnetservice.h @@ -90,7 +90,7 @@ public: const RsServiceInfo serviceInfo, RsGixsReputation* reputations = NULL, RsGcxs* circles = NULL, RsGixs *gixs=NULL, PgpAuxUtils *pgpUtils = NULL, - bool grpAutoSync = true, bool msgAutoSync = true, + bool grpAutoSync = true, bool msgAutoSync = true,bool distSync=false, uint32_t default_store_period = RS_GXS_DEFAULT_MSG_STORE_PERIOD, uint32_t default_sync_period = RS_GXS_DEFAULT_MSG_REQ_PERIOD); @@ -543,6 +543,7 @@ private: PgpAuxUtils *mPgpUtils; bool mGrpAutoSync; bool mAllowMsgSync; + bool mAllowDistSync; // need to be verfied std::vector mPendingResp; diff --git a/libretroshare/src/gxs/rsgxsnettunnel.cc b/libretroshare/src/gxs/rsgxsnettunnel.cc index 36ac81f47..6d763a092 100644 --- a/libretroshare/src/gxs/rsgxsnettunnel.cc +++ b/libretroshare/src/gxs/rsgxsnettunnel.cc @@ -57,6 +57,7 @@ RsGxsNetTunnelVirtualPeerInfo::~RsGxsNetTunnelVirtualPeerInfo() const uint16_t RS_SERVICE_TYPE_GXS_NET_TUNNEL = 0x2233 ; const uint8_t RS_PKT_SUBTYPE_GXS_NET_TUNNEL_VIRTUAL_PEER = 0x01 ; +const uint8_t RS_PKT_SUBTYPE_GXS_NET_TUNNEL_KEEP_ALIVE = 0x02 ; class RsGxsNetTunnelItem: public RsItem { @@ -74,7 +75,6 @@ class RsGxsNetTunnelVirtualPeerItem: public RsGxsNetTunnelItem { public: RsGxsNetTunnelVirtualPeerItem() :RsGxsNetTunnelItem(RS_PKT_SUBTYPE_GXS_NET_TUNNEL_VIRTUAL_PEER) {} - explicit RsGxsNetTunnelVirtualPeerItem(uint8_t subtype) :RsGxsNetTunnelItem(subtype) {} virtual ~RsGxsNetTunnelVirtualPeerItem() {} @@ -86,6 +86,15 @@ public: RsPeerId virtual_peer_id ; }; +class RsGxsNetTunnelKeepAliveItem: public RsGxsNetTunnelItem +{ +public: + RsGxsNetTunnelKeepAliveItem() :RsGxsNetTunnelItem(RS_PKT_SUBTYPE_GXS_NET_TUNNEL_KEEP_ALIVE) {} + + virtual ~RsGxsNetTunnelKeepAliveItem() {} + virtual void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) {} +}; + class RsGxsNetTunnelSerializer: public RsServiceSerializer { public: @@ -102,6 +111,7 @@ public: switch(item_subtype) { case RS_PKT_SUBTYPE_GXS_NET_TUNNEL_VIRTUAL_PEER: return new RsGxsNetTunnelVirtualPeerItem ; + case RS_PKT_SUBTYPE_GXS_NET_TUNNEL_KEEP_ALIVE : return new RsGxsNetTunnelKeepAliveItem ; default: GXS_NET_TUNNEL_ERROR() << "type ID " << std::hex << item_subtype << std::dec << " is not handled!" << std::endl; return NULL ; @@ -113,71 +123,19 @@ public: // Interface with rest of the software // //===========================================================================================================================================// -bool RsGxsNetTunnelService::manage(const RsGxsGroupId& group_id) -{ - RsFileHash hash = calculateGroupHash(group_id) ; - - RsStackMutex stack(mGxsNetTunnelMtx); /********** STACK LOCKED MTX ******/ - - RsGxsNetTunnelGroupInfo& info(mGroups[group_id]) ; - - time_t now = time(NULL) ; - - if(info.group_status == RsGxsNetTunnelGroupInfo::RS_GXS_NET_TUNNEL_GRP_STATUS_VPIDS_AVAILABLE) - return true; - - info.hash = hash ; - info.last_contact = now ; - info.group_status = RsGxsNetTunnelGroupInfo::RS_GXS_NET_TUNNEL_GRP_STATUS_TUNNELS_REQUESTED; - - mHandledHashes[hash] = group_id ; - -#ifdef DEBUG_GXS_TUNNEL - GXS_NET_TUNNEL_DEBUG() << "Asking turtle router to monitor tunnels for hash " << hash << std::endl; -#endif - - // Now ask the turtle router to manage a tunnel for that hash. - - mTurtle->monitorTunnels(hash,this,false) ; - - return true; -} - -bool RsGxsNetTunnelService::release(const RsGxsGroupId& group_id) -{ - RsStackMutex stack(mGxsNetTunnelMtx); /********** STACK LOCKED MTX ******/ - - // Here we need to clean the stuff that was created by this group id. - - auto it = mGroups.find(group_id) ; - - if(it == mGroups.end()) - { - GXS_NET_TUNNEL_ERROR() << "RsGxsNetTunnelService::release(): Weird. Cannot release client group " << group_id << " that is not known." << std::endl; - return false ; - } - - mGroups.erase(it) ; - - RsFileHash hash = calculateGroupHash(group_id) ; - - mHandledHashes.erase(hash) ; - return true ; -} - -class ItemAutoDelete +class DataAutoDelete { public: - ItemAutoDelete(RsItem *& item) : mItem(item) {} - ~ItemAutoDelete() { delete mItem; mItem=NULL ; } - RsItem *& mItem; + DataAutoDelete(unsigned char *& data) : mData(data) {} + ~DataAutoDelete() { free(mData); mData=NULL ; } + unsigned char *& mData; }; -bool RsGxsNetTunnelService::sendItem(RsItem *& item,const RsGxsNetTunnelVirtualPeerId& virtual_peer) +bool RsGxsNetTunnelService::sendData(unsigned char *& data,uint32_t data_len,const RsGxsNetTunnelVirtualPeerId& virtual_peer) { // The item is serialized and encrypted using chacha20+SHA256, using the generic turtle encryption, and then sent to the turtle router. - ItemAutoDelete iad(item) ; // This ensures the item is deleted whatsoever when leaving + DataAutoDelete iad(data) ; // This ensures the item is deleted whatsoever when leaving // 1 - find the virtual peer and the proper master key to encrypt with, and check that all the info is known @@ -215,10 +173,7 @@ bool RsGxsNetTunnelService::sendItem(RsItem *& item,const RsGxsNetTunnelVirtualP RsTurtleGenericDataItem *encrypted_turtle_item = NULL ; - uint32_t serialized_size = 0; // TODO - RsTemporaryMemory data(serialized_size) ; - - if(!p3turtle::encryptData(data,serialized_size,it3->second.encryption_master_key,encrypted_turtle_item)) + if(!p3turtle::encryptData(data,data_len,it3->second.encryption_master_key,encrypted_turtle_item)) { GXS_NET_TUNNEL_ERROR() << "cannot encrypt. Something's wrong. Data is dropped." << std::endl; return false ; @@ -229,11 +184,63 @@ bool RsGxsNetTunnelService::sendItem(RsItem *& item,const RsGxsNetTunnelVirtualP return true ; } -bool RsGxsNetTunnelService::getVirtualPeers(const RsGxsGroupId&, std::list& peers) +bool RsGxsNetTunnelService::getVirtualPeers(const RsGxsGroupId& group_id, std::list& peers) { - // returns the virtual peers for this group - GXS_NET_TUNNEL_NOT_IMPLEMENTED(); - return false ; + // This function has two effects: + // - return the virtual peers for this group + // - passively set the group as "managed", so that it we answer tunnel requests. + + RS_STACK_MUTEX(mGxsNetTunnelMtx); + + // update the hash entry if needed + + RsFileHash hash = calculateGroupHash(group_id); + mHandledHashes[hash] = group_id ; + + // Create the group entry, if needed, with passive mode. + + RsGxsNetTunnelGroupInfo& ginfo( mGroups[group_id] ) ; + + ginfo.hash = hash ; + + for(auto it2 = ginfo.virtual_peers.begin();it2 != ginfo.virtual_peers.end();++it2) + if(it2->second.vpid_status == RsGxsNetTunnelVirtualPeerInfo::RS_GXS_NET_TUNNEL_VP_STATUS_ACTIVE) + peers.push_back(it2->second.net_service_virtual_peer) ; + +#ifdef DEBUG_GXS_TUNNEL + GXS_NET_TUNNEL_DEBUG() << "returning " << peers.size() << " peers." << std::endl; +#endif + + return true ; +} + +bool RsGxsNetTunnelService::requestPeers(const RsGxsGroupId& group_id) +{ + RS_STACK_MUTEX(mGxsNetTunnelMtx); + + // Now ask the turtle router to manage a tunnel for that hash. + + RsGxsNetTunnelGroupInfo& ginfo( mGroups[group_id] ) ; + + ginfo.group_policy = RsGxsNetTunnelGroupInfo::RS_GXS_NET_TUNNEL_GRP_POLICY_ACTIVE; + + // we dont set the group policy here. It will only be set if no peers, or too few peers are available. + + return true; +} + +bool RsGxsNetTunnelService::releasePeers(const RsGxsGroupId& group_id) +{ + RS_STACK_MUTEX(mGxsNetTunnelMtx); + + // Ask turtle router to stop requesting tunnels for that hash. + + RsGxsNetTunnelGroupInfo& ginfo( mGroups[group_id] ) ; + + ginfo.group_policy = RsGxsNetTunnelGroupInfo::RS_GXS_NET_TUNNEL_GRP_POLICY_PASSIVE; + mTurtle->stopMonitoringTunnels(ginfo.hash) ; + + return true; } RsGxsNetTunnelVirtualPeerId RsGxsNetTunnelService::makeServerVirtualPeerIdForGroup(const RsGxsGroupId& group_id) const @@ -304,14 +311,9 @@ void RsGxsNetTunnelService::connectToTurtleRouter(p3turtle *tr) bool RsGxsNetTunnelService::handleTunnelRequest(const RsFileHash &hash,const RsPeerId& peer_id) { - GXS_NET_TUNNEL_NOT_IMPLEMENTED(); + // We simply check for wether a managed group has a hash that corresponds to the given hash. - // at this point we need to talk to the client services - // There's 2 ways to do that: - // 1 - client services "register" and we ask them one by one. - // 2 - client service derives from RsGxsNetTunnelService and the client is interrogated using an overloaded virtual method - - return true ; + return mHandledHashes.find(hash) != mHandledHashes.end(); } void RsGxsNetTunnelService::receiveTurtleData(RsTurtleGenericTunnelItem *item,const RsFileHash& hash,const RsPeerId& virtual_peer_id,RsTurtleGenericTunnelItem::Direction direction) @@ -437,23 +439,27 @@ void RsGxsNetTunnelService::addVirtualPeer(const TurtleFileHash& hash, const Tur generateEncryptionKey(group_id,vpid,vpinfo.encryption_master_key ); - // If we're a server, we need to send our own virtual peer id to the client + // We need to send our own virtual peer id to the other end of the tunnel - if(dir == RsTurtleGenericTunnelItem::DIRECTION_CLIENT) - { - vpinfo.net_service_virtual_peer = makeServerVirtualPeerIdForGroup(group_id); + vpinfo.net_service_virtual_peer = makeServerVirtualPeerIdForGroup(group_id); #ifdef DEBUG_RSGXSNETTUNNEL - GXS_NET_TUNNEL_DEBUG() << " peer is server side: sending back virtual peer name " << vpinfo.net_service_virtual_peer << std::endl; + GXS_NET_TUNNEL_DEBUG() << " sending back virtual peer name " << vpinfo.net_service_virtual_peer << " to end of tunnel" << std::endl; #endif - RsGxsNetTunnelVirtualPeerItem *pitem = new RsGxsNetTunnelVirtualPeerItem ; + RsGxsNetTunnelVirtualPeerItem pitem ; + pitem.virtual_peer_id = vpinfo.net_service_virtual_peer ; - pitem->virtual_peer_id = vpinfo.net_service_virtual_peer ; + RsTemporaryMemory tmpmem( RsGxsNetTunnelSerializer().size(&pitem) ) ; + uint32_t len = tmpmem.size(); - vpinfo.outgoing_items.push_back(pitem) ; - } + RsGxsNetTunnelSerializer().serialise(&pitem,tmpmem,&len); + + RsTurtleGenericDataItem *encrypted_turtle_item = NULL ; + + if(p3turtle::encryptData(tmpmem,len,vpinfo.encryption_master_key,encrypted_turtle_item)) + mTurtle->sendTurtleData(vpid,encrypted_turtle_item) ; else - vpinfo.net_service_virtual_peer.clear(); + GXS_NET_TUNNEL_ERROR() << "cannot encrypt. Something's wrong. Data is dropped." << std::endl; } void RsGxsNetTunnelService::removeVirtualPeer(const TurtleFileHash& hash, const TurtleVirtualPeerId& vpid) @@ -531,6 +537,12 @@ void RsGxsNetTunnelService::autowash() { } +// info.group_status = RsGxsNetTunnelGroupInfo::RS_GXS_NET_TUNNEL_GRP_STATUS_TUNNELS_REQUESTED; +// +// mTurtle->monitorTunnels(hash,this,false) ; +// info.group_status = RsGxsNetTunnelGroupInfo::RS_GXS_NET_TUNNEL_GRP_STATUS_TUNNELS_REQUESTED; + + // void RsGxsNetTunnelService::handleIncoming(const RsGxsTunnelId& tunnel_id,RsGxsTunnelItem *item) // { // #ifdef DEBUG_RSGXSNETTUNNEL diff --git a/libretroshare/src/gxs/rsgxsnettunnel.h b/libretroshare/src/gxs/rsgxsnettunnel.h index 798b49f1e..901aba61d 100644 --- a/libretroshare/src/gxs/rsgxsnettunnel.h +++ b/libretroshare/src/gxs/rsgxsnettunnel.h @@ -34,6 +34,10 @@ * * It is the responsibility of RsGxsNetService to activate/desactivate tunnels for each particular group, depending on wether the group * is already available at friends or not. + * + * Tunnel management is done at the level of groups rather than services, because we would like to keep the possibility to not + * request tunnels for some groups which do not need it, and only request tunnels for specific groups that cannot be provided + * by direct connections. */ // Protocol: @@ -61,8 +65,23 @@ // Client <------------------- GXS Data ------------------> Server | // - // Notes: -// * tunnels are only used one-way. If a distant peers wants to sync the same group, he'll have to open his own tunnel, with a different ID. -// * each group will produced multiple tunnels, but each tunnel with have exactly one virtual peer ID +// * tunnels are established symetrically. If a distant peers wants to sync the same group, they'll have to open a single tunnel, with a different ID. +// Groups therefore have two states: +// - managed : the group can be used to answer tunnel requests. If server tunnels are established, the group will be synced with these peers +// - tunneled: the group will actively request tunnels. If tunnels are established both ways, the same virtual peers will be used so the tunnels are "merged". +// * In practice, that means one of the two tunnels will not be used and therefore die. +// * If a tunneled group already has enough virtual peers, it will not request for tunnels itself. +// +// Group policy | Request tunnels | SyncWithPeers | Item receipt +// --------------------+-------------------+-----------------------+---------------- +// Passive | no | If peers present | If peers present +// Active | yes, if no peers | If peers present | If peers present +// | | | +// +// * when a service has the DistSync flag set, groups to sync are communicated passively to the GxsNetTunnel service when requesting distant peers. +// However, a call should be made to set a particular group policy to "ACTIVE" for group that do not have peers and need some. +// +// * services also need to retrieve GXS data items that come out of tunnels. These will be available as (data,len) type, since they are not de-serialized. typedef RsPeerId RsGxsNetTunnelVirtualPeerId ; @@ -75,7 +94,7 @@ struct RsGxsNetTunnelVirtualPeerInfo RS_GXS_NET_TUNNEL_VP_STATUS_ACTIVE = 0x02 // virtual peer id is known. Data can transfer. }; - RsGxsNetTunnelVirtualPeerInfo() : vpid_status(RS_GXS_NET_TUNNEL_VP_STATUS_UNKNOWN) { memset(encryption_master_key,0,16) ; } + RsGxsNetTunnelVirtualPeerInfo() : vpid_status(RS_GXS_NET_TUNNEL_VP_STATUS_UNKNOWN) { memset(encryption_master_key,0,32) ; } ~RsGxsNetTunnelVirtualPeerInfo() ; uint8_t vpid_status ; // status of the peer @@ -92,14 +111,23 @@ struct RsGxsNetTunnelVirtualPeerInfo struct RsGxsNetTunnelGroupInfo { - enum { RS_GXS_NET_TUNNEL_GRP_STATUS_UNKNOWN = 0x00, // unknown status - RS_GXS_NET_TUNNEL_GRP_STATUS_TUNNELS_REQUESTED = 0x01, // waiting for turtle to send some virtual peers. - RS_GXS_NET_TUNNEL_GRP_STATUS_VPIDS_AVAILABLE = 0x02 // some virtual peers are available + enum GroupStatus { + RS_GXS_NET_TUNNEL_GRP_STATUS_UNKNOWN = 0x00, // unknown status + RS_GXS_NET_TUNNEL_GRP_STATUS_IDLE = 0x01, // no virtual peers requested, just waiting + RS_GXS_NET_TUNNEL_GRP_STATUS_TUNNELS_REQUESTED = 0x02, // virtual peers requested, and waiting for turtle to answer + RS_GXS_NET_TUNNEL_GRP_STATUS_VPIDS_AVAILABLE = 0x03 // some virtual peers are available. Data can be read/written }; - RsGxsNetTunnelGroupInfo() : group_status(RS_GXS_NET_TUNNEL_GRP_STATUS_UNKNOWN),last_contact(0) {} + enum GroupPolicy { + RS_GXS_NET_TUNNEL_GRP_POLICY_UNKNOWN = 0x00, // nothing has been set + RS_GXS_NET_TUNNEL_GRP_POLICY_PASSIVE = 0x01, // group is available for server side tunnels, but does not explicitely request tunnels + RS_GXS_NET_TUNNEL_GRP_POLICY_ACTIVE = 0x02, // group explicitely request tunnels, if none available + }; - uint8_t group_status ; + RsGxsNetTunnelGroupInfo() : group_policy(RS_GXS_NET_TUNNEL_GRP_POLICY_PASSIVE),group_status(RS_GXS_NET_TUNNEL_GRP_STATUS_IDLE),last_contact(0) {} + + GroupPolicy group_policy ; + GroupStatus group_status ; time_t last_contact ; TurtleFileHash hash ; @@ -112,27 +140,32 @@ public: RsGxsNetTunnelService() ; /*! - * \brief start managing tunnels for this group - * @param group_id group for which tunnels should be requested + * \brief Manage tunnels for this group + * @param group_id group for which tunnels should be released */ - bool manage(const RsGxsGroupId& group_id) ; + bool requestPeers(const RsGxsGroupId&group_id) ; /*! * \brief Stop managing tunnels for this group * @param group_id group for which tunnels should be released */ - bool release(const RsGxsGroupId&group_id) ; - + bool releasePeers(const RsGxsGroupId&group_id) ; /*! - * \brief sendItem + * \brief Get the list of active virtual peers for a given group. This implies that a tunnel is up and + * alive. This function also "registers" the group which allows to handle tunnel requests in the server side. + */ + bool getVirtualPeers(const RsGxsGroupId& group_id, std::list& peers) ; // returns the virtual peers for this group + + /*! + * \brief sendData * send data to this virtual peer, and takes memory ownership (deletes the item) * \param item item to send * \param virtual_peer destination virtual peer * \return * true if succeeded. */ - bool sendItem(RsItem *& item, const RsGxsNetTunnelVirtualPeerId& virtual_peer) ; + bool sendData(unsigned char *& data, uint32_t data_len, const RsGxsNetTunnelVirtualPeerId& virtual_peer) ; /*! * \brief receivedItem @@ -142,12 +175,6 @@ public: */ RsItem *receivedItem(const RsGxsNetTunnelVirtualPeerId& virtual_peer) ; - /*! - * \brief Get the list of active virtual peers for a given group. This implies that the tunnel is up and - * alive. - */ - bool getVirtualPeers(const RsGxsGroupId&, std::list& peers) ; // returns the virtual peers for this group - /*! * \brief dumps all information about monitored groups. */