finished implementation of GxsNetTunnel service

This commit is contained in:
csoler 2018-03-29 10:54:58 +02:00
parent b488760d7d
commit 73b04f3109
No known key found for this signature in database
GPG Key ID: 7BCA522266C0804C
4 changed files with 148 additions and 108 deletions

View File

@ -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)
{

View File

@ -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<AuthorPending*> mPendingResp;

View File

@ -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<RsPeerId>& peers)
bool RsGxsNetTunnelService::getVirtualPeers(const RsGxsGroupId& group_id, std::list<RsGxsNetTunnelVirtualPeerId>& 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

View File

@ -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<RsGxsNetTunnelVirtualPeerId>& 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<RsPeerId>& peers) ; // returns the virtual peers for this group
/*!
* \brief dumps all information about monitored groups.
*/