saving ongoing work. Implementation almoast finished.

This commit is contained in:
csoler 2015-11-22 23:19:46 -05:00
parent 8df9d4be04
commit 5c0f1dac08
4 changed files with 101 additions and 27 deletions

View File

@ -82,11 +82,12 @@ void p3GxsTunnelService::flush()
time_t now = time(NULL) ;
for(std::map<RsGxsId,GxsTunnelPeerInfo>::iterator it(_gxs_tunnel_contacts.begin());it!=_gxs_tunnel_contacts.end();++it)
for(std::map<RsGxsTunnelId,GxsTunnelPeerInfo>::iterator it(_gxs_tunnel_contacts.begin());it!=_gxs_tunnel_contacts.end();++it)
{
if(it->second.last_contact+20+GXS_TUNNEL_KEEP_ALIVE_TIMEOUT < now && it->second.status == RS_GXS_TUNNEL_STATUS_CAN_TALK)
{
std::cerr << "(II) GxsTunnelService:: connexion interrupted with peer." << std::endl;
it->second.status = RS_GXS_TUNNEL_STATUS_TUNNEL_DN ;
it->second.virtual_peer_id.clear() ;
@ -232,7 +233,7 @@ void p3GxsTunnelService::addVirtualPeer(const TurtleFileHash& hash,const TurtleV
else // client side
{
RsGxsId to_gxs_id = gxsIdFromHash(hash) ;
std::map<RsGxsId,GxsTunnelPeerInfo>::const_iterator it = _gxs_tunnel_contacts.find(to_gxs_id) ;
std::map<RsGxsTunnelId,GxsTunnelPeerInfo>::const_iterator it = _gxs_tunnel_contacts.find(to_gxs_id) ;
if(it == _gxs_tunnel_contacts.end())
{
@ -273,6 +274,7 @@ void p3GxsTunnelService::locked_restartDHSession(const RsPeerId& virtual_peer_id
GxsTunnelDHInfo& dhinfo = _gxs_tunnel_virtual_peer_ids[virtual_peer_id] ;
dhinfo.status = RS_GXS_TUNNEL_DH_STATUS_UNINITIALIZED ;
dhinfo.own_gxs_id = own_gxs_id ;
if(!locked_initDHSessionKey(dhinfo.dh))
{
@ -313,7 +315,7 @@ void p3GxsTunnelService::removeVirtualPeer(const TurtleFileHash& hash,const Turt
DH_free(it->second.dh) ;
_gxs_tunnel_virtual_peer_ids.erase(it) ;
std::map<RsGxsId,GxsTunnelPeerInfo>::iterator it2 = _gxs_tunnel_contacts.find(gxs_id) ;
std::map<RsGxsTunnelId,GxsTunnelPeerInfo>::iterator it2 = _gxs_tunnel_contacts.find(gxs_id) ;
if(it2 == _gxs_tunnel_contacts.end())
{
@ -436,7 +438,7 @@ bool p3GxsTunnelService::handleEncryptedData(const uint8_t *data_bytes,uint32_t
}
RsGxsId gxs_id = it->second.gxs_id ;
std::map<RsGxsId,GxsTunnelPeerInfo>::iterator it2 = _gxs_tunnel_contacts.find(gxs_id) ;
std::map<RsGxsTunnelId,GxsTunnelPeerInfo>::iterator it2 = _gxs_tunnel_contacts.find(gxs_id) ;
if(it2 == _gxs_tunnel_contacts.end())
{
@ -636,22 +638,25 @@ void p3GxsTunnelService::handleRecvDHPublicKey(RsGxsTunnelDHPublicKeyItem *item)
#ifdef DEBUG_GXS_TUNNEL
std::cerr << " DH key computation successed. New key in place." << std::endl;
#endif
GxsTunnelPeerInfo& pinfo(_gxs_tunnel_contacts[senders_id]) ;
// make a hash of destination and source GXS ids in order to create the tunnel name
RsGxsId own_id = it->second.own_gxs_id ;
RsGxsTunnelId tunnel_id = makeGxsTunnelId(own_id,senders_id) ;
GxsTunnelPeerInfo& pinfo(_gxs_tunnel_contacts[tunnel_id]) ;
// Now hash the key buffer into a 16 bytes key.
assert(GXS_TUNNEL_AES_KEY_SIZE <= Sha1CheckSum::SIZE_IN_BYTES) ;
memcpy(pinfo.aes_key, RsDirUtil::sha1sum(key_buff,size).toByteArray(),GXS_TUNNEL_AES_KEY_SIZE) ;
delete[] key_buff ;
pinfo.last_contact = time(NULL) ;
pinfo.last_keep_alive_sent = time(NULL) ;
pinfo.status = RS_GXS_TUNNEL_STATUS_CAN_TALK ;
pinfo.virtual_peer_id = vpid ;
pinfo.direction = it->second.direction ;
if(pinfo.direction == RsTurtleGenericTunnelItem::DIRECTION_CLIENT)
pinfo.own_gxs_id = gxsIdFromHash(it->second.hash) ;
pinfo.own_gxs_id = own_id ;
#ifdef DEBUG_GXS_TUNNEL
std::cerr << " DH key computed. Tunnel is now secured!" << std::endl;
@ -676,6 +681,29 @@ void p3GxsTunnelService::handleRecvDHPublicKey(RsGxsTunnelDHPublicKeyItem *item)
//RsServer::notify()->notifyListChange(NOTIFY_LIST_PRIVATE_INCOMING_CHAT, NOTIFY_TYPE_ADD);
}
RsGxsTunnelId p3GxsTunnelService::makeGxsTunnelId(const RsGxsId& own_id,const RsGxsId& distant_id) const
{
unsigned char mem[RsGxsId::SIZE_IN_BYTES * 2] ;
// Always sort the ids, as a matter to avoid confusion between the two. Also that generates the same tunnel ID on both sides
// which helps debugging. If the code is right this is not needed anyway.
if(own_id < distant_id)
{
memcpy(mem, own_id.toBytesArray(), RsGxsId::SIZE_IN_BYTES) ;
memcpy(mem+RsGxsId::SIZE_IN_BYTES, distant_id.toBytesArray(), RsGxsId::SIZE_IN_BYTES) ;
}
else
{
memcpy(mem, distant_id.toBytesArray(), RsGxsId::SIZE_IN_BYTES) ;
memcpy(mem+RsGxsId::SIZE_IN_BYTES, own_id.toBytesArray(), RsGxsId::SIZE_IN_BYTES) ;
}
assert( RsGxsTunnelId::SIZE_IN_BYTES <= Sha1CheckSum::SIZE_IN_BYTES ) ;
return RsGxsTunnelId( RsUtil::sha1sum(mem, 2*RsGxsId::SIZE_IN_BYTES).toByteArray() ) ;
}
bool p3GxsTunnelService::locked_sendDHPublicKey(const DH *dh,const RsGxsId& own_gxs_id,const RsPeerId& virtual_peer_id)
{
if(dh == NULL)
@ -847,7 +875,7 @@ void p3GxsTunnelService::sendEncryptedTurtleData(const uint8_t *buff,uint32_t rs
#endif
RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/
std::map<RsGxsId,GxsTunnelPeerInfo>::iterator it = _gxs_tunnel_contacts.find(gxs_id) ;
std::map<RsGxsTunnelId,GxsTunnelPeerInfo>::iterator it = _gxs_tunnel_contacts.find(gxs_id) ;
if(it == _gxs_tunnel_contacts.end())
{
@ -912,7 +940,7 @@ void p3GxsTunnelService::sendEncryptedTurtleData(const uint8_t *buff,uint32_t rs
mTurtle->sendTurtleData(virtual_peer_id,gitem) ;
}
bool p3GxsTunnelService::requestSecuredTunnel(const RsGxsId& to_gxs_id,const RsGxsId& from_gxs_id,RsGxsTunnelClientService *client,uint32_t& error_code)
bool p3GxsTunnelService::requestSecuredTunnel(const RsGxsId& to_gxs_id, const RsGxsId& from_gxs_id, RsGxsTunnelId &tunnel_id, uint32_t& error_code)
{
// should be a parameter.
@ -942,14 +970,17 @@ bool p3GxsTunnelService::requestSecuredTunnel(const RsGxsId& to_gxs_id,const RsG
return true ;
}
void p3GxsTunnelService::startClientGxsTunnelConnection(const RsGxsId& to_gxs_id,const RsGxsId& from_gxs_id)
void p3GxsTunnelService::startClientGxsTunnelConnection(const RsGxsId& to_gxs_id,const RsGxsId& from_gxs_id,RsGxsTunnelId& tunnel_id)
{
RsGxsTunnelId tnl_id = makeGxsTunnelId(from_gxs_id,to_gxs_id) ;
tunnel_id = tnl_id ;
{
RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/
if(_gxs_tunnel_contacts.find(to_gxs_id) != _gxs_tunnel_contacts.end())
if(_gxs_tunnel_contacts.find(tunnel_id) != _gxs_tunnel_contacts.end())
{
std::cerr << "GxsTunnelService:: asking distant chat connexion to a peer who's already in a chat. Ignoring." << std::endl;
std::cerr << "GxsTunnelService:: asking GXS tunnel for a configuration that already exits.Ignoring." << std::endl;
return ;
}
}
@ -961,6 +992,7 @@ void p3GxsTunnelService::startClientGxsTunnelConnection(const RsGxsId& to_gxs_id
info.last_keep_alive_sent = now ;
info.status = RS_GXS_TUNNEL_STATUS_TUNNEL_DN ;
info.own_gxs_id = from_gxs_id ;
info.to_gxs_id = to_gxs_id ;
info.direction = RsTurtleGenericTunnelItem::DIRECTION_SERVER ;
info.virtual_peer_id.clear();
@ -968,11 +1000,13 @@ void p3GxsTunnelService::startClientGxsTunnelConnection(const RsGxsId& to_gxs_id
{
RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/
_gxs_tunnel_contacts[to_gxs_id] = info ;
_gxs_tunnel_contacts[tnt_id] = info ;
}
// Now ask the turtle router to manage a tunnel for that hash.
#warning need to make sure that we can ask the same hash if the from ID is different. What's going to happen??
RsFileHash hash = hashFromGxsId(to_gxs_id) ;
#ifdef DEBUG_GXS_TUNNEL
std::cerr << "Starting distant chat to " << to_gxs_id << ", hash = " << hash << ", from " << from_gxs_id << std::endl;
@ -1032,7 +1066,7 @@ bool p3GxsTunnelService::getTunnelStatus(const RsGxsId& gxs_id,uint32_t& status,
{
RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/
std::map<RsGxsId,GxsTunnelPeerInfo>::const_iterator it = _gxs_tunnel_contacts.find(gxs_id) ;
std::map<RsGxsTunnelId,GxsTunnelPeerInfo>::const_iterator it = _gxs_tunnel_contacts.find(gxs_id) ;
if(it != _gxs_tunnel_contacts.end())
{
@ -1049,7 +1083,7 @@ bool p3GxsTunnelService::getTunnelStatus(const RsGxsId& gxs_id,uint32_t& status,
return false ;
}
bool p3GxsTunnelService::closeExistingTunnel(const RsGxsId& gxs_id)
bool p3GxsTunnelService::closeExistingTunnel(const RsGxsTunnelId& tunnel_id)
{
// two cases:
// - client needs to stop asking for tunnels => remove the hash from the list of tunnelled files
@ -1058,7 +1092,7 @@ bool p3GxsTunnelService::closeExistingTunnel(const RsGxsId& gxs_id)
{
RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/
std::map<RsGxsId,GxsTunnelPeerInfo>::const_iterator it = _gxs_tunnel_contacts.find(gxs_id) ;
std::map<RsGxsTunnelId,GxsTunnelPeerInfo>::const_iterator it = _gxs_tunnel_contacts.find(gxs_id) ;
if(it == _gxs_tunnel_contacts.end())
{

View File

@ -51,6 +51,42 @@
//
// Data is send to a service ID (could be any existing service ID). The endpoint of the tunnel must register each service, in order to
// allow the data to be transmitted/sent from/to that service. Otherwise an error is issued.
//
// Algorithms
//
// Tunnel establishment
// * we need to layers: the turtle layer, and the GXS id layer.
// * at the turtle layer:
// - accept virtual peers from turtle tunnel service. The hash for that VP only depends on the server GXS id at server side, which is our
// own ID at server side, and destination ID at client side. What happens if two different clients request to talk to the same GXS id? (same hash)
// They should use different virtual peers, so it should be ok.
// - multiple tunnels may end up to the same hash, but will correspond to different GXS tunnels since the GXS id in the other side is different.
//
// * at the GXS layer
// - we should be able to have as many tunnels as they are different couples of GXS ids to interact. That means the tunnel should be determined
// by a mix between our own GXS id and the GXS id we're talking to. That is what the TunnelVirtualPeer is.
//
//
// RequestTunnel(source_own_id,destination_id)
// |
// +---------------------------> p3Turtle::monitorTunnels( hash(destination_id) )
// |
// [Turtle async work] -------------------+
// | |
// handleTunnelRequest() <-----------------------------------------------+ |
// | |
// +---------------- keep record in _gxs_tunnel_virtual_peer_id, initiate DH exchange |
// |
// handleDHPublicKey() <-----------------------------------------------------------------------------+
// |
// +---------------- update _gxs_tunnel_contacts[ tunnel_hash = hash(own_id, destination_id) ]
// |
// +---------------- notify client service that Peer(destination_id, tunnel_hash) is ready to talk to
//
// Notes
// * one other option would be to make the turtle hash depend on both GXS ids in a way that it is possible to find which are the two ids on the server side.
// but that would prevent the use of unknown IDs, which we would like to offer as well.
#include <turtle/turtleclientservice.h>
#include <retroshare/rsgxstunnel.h>
@ -74,9 +110,9 @@ public:
// 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.
//
virtual bool requestSecuredTunnel(const RsGxsId& to_id,const RsGxsId& from_id,RsGxsTunnelClientService *client,uint32_t& error_code) ;
virtual bool closeExistingTunnel(const RsGxsId& pid) ;
virtual bool getTunnelStatus(const RsGxsId &gxs_id,uint32_t &status, RsGxsId *from_gxs_id=NULL) ;
virtual bool requestSecuredTunnel(const RsGxsId& to_id,const RsGxsId& from_id,RsGxsTunnelId& tunnel_id,uint32_t& error_code) ;
virtual bool closeExistingTunnel(const RsGxsTunnelId &tunnel_id) ;
virtual bool getTunnelStatus(const RsGxsTunnelId& tunnel_id,uint32_t &status);
private:
void flush() ;
@ -108,6 +144,7 @@ private:
DH *dh ;
RsGxsId gxs_id ;
RsGxsId own_gxs_id ;
RsTurtleGenericTunnelItem::Direction direction ;
uint32_t status ;
TurtleFileHash hash ;
@ -115,7 +152,7 @@ private:
// This maps contains the current peers to talk to with distant chat.
//
std::map<RsGxsId, GxsTunnelPeerInfo> _gxs_tunnel_contacts ; // current peers we can talk to
std::map<RsGxsTunnelId,GxsTunnelPeerInfo> _gxs_tunnel_contacts ; // current peers we can talk to
std::map<RsPeerId,GxsTunnelDHInfo> _gxs_tunnel_virtual_peer_ids ; // current virtual peers. Used to figure out tunnels, etc.
// List of items to be sent asap. Used to store items that we cannot pass directly to
@ -133,7 +170,7 @@ private:
// session handling handles
void markGxsTunnelAsClosed(const RsGxsId &gxs_id) ;
void startClientGxsTunnelConnection(const RsGxsId &to_gxs_id, const RsGxsId& from_gxs_id) ;
void startClientGxsTunnelConnection(const RsGxsId &to_gxs_id, const RsGxsId& from_gxs_id, RsGxsTunnelId &tunnel_id) ;
void locked_restartDHSession(const RsPeerId &virtual_peer_id, const RsGxsId &own_gxs_id) ;
// utility functions
@ -148,6 +185,7 @@ 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

View File

@ -36,7 +36,7 @@ public:
static const uint32_t RS_GXS_TUNNEL_ERROR_NO_ERROR = 0x0000 ;
static const uint32_t RS_GXS_TUNNEL_ERROR_UNKNOWN_GXS_ID = 0x0001 ;
typedef TurtleVirtualPeerId RsGxsTunnelId ;
typedef GXSTunnelId RsGxsTunnelId ;
class RsGxsTunnelClientService
{
@ -44,12 +44,12 @@ public:
// The client should derive this in order to handle notifications from the tunnel service.
// This cannot be ignored because the client needs to know when the tunnel is active.
virtual void notifyTunnelStatus(const RsGxsId& id,uint32_t tunnel_status) =0;
virtual void notifyTunnelStatus(const RsGxsTunnelId& tunnel_id,uint32_t tunnel_status) =0;
// Data obtained from the corresponding GXS id. The memory ownership is transferred to the client, which
// is responsible to free it using free() once used.
virtual void receiveData(const RsGxsId& id,unsigned char *data,uint32_t data_size) =0;
virtual void receiveData(const RsGxsTunnelId& id,const RsGxsId& from_id,unsigned char *data,uint32_t data_size) =0;
};
class GxsTunnelInfo
@ -88,7 +88,7 @@ public:
// When the tunnel is secured, the client---here supplied as argument---will be notified. He can
// then send data into the tunnel. The same tunnel may be used by different clients.
virtual bool requestSecuredTunnel(const RsGxsId& to_id,const RsGxsId& from_id,uint32_t& error_code) =0 ;
virtual bool requestSecuredTunnel(const RsGxsId& to_id,const RsGxsId& from_id,RsGxsTunnelId& tunnel_id,uint32_t& error_code) =0 ;
// Data is sent through the established tunnel, possibly multiple times, until reception is acknowledged. If the tunnel does not exist, the item is rejected and
// an error is issued. In any case, the memory ownership of the data is transferred to the tunnel service, so the client should not use it afterwards.

View File

@ -218,6 +218,7 @@ static const uint32_t RS_GENERIC_ID_GXS_ID_TYPE = 0x0006 ;
static const uint32_t RS_GENERIC_ID_GXS_MSG_ID_TYPE = 0x0007 ;
static const uint32_t RS_GENERIC_ID_GXS_CIRCLE_ID_TYPE = 0x0008 ;
static const uint32_t RS_GENERIC_ID_GROUTER_ID_TYPE = 0x0009 ;
static const uint32_t RS_GENERIC_ID_GXS_TUNNEL_ID_TYPE = 0x0010 ;
typedef t_RsGenericIdType< SSL_ID_SIZE , false, RS_GENERIC_ID_SSL_ID_TYPE> SSLIdType ;
typedef t_RsGenericIdType< PGP_KEY_ID_SIZE , true, RS_GENERIC_ID_PGP_ID_TYPE> PGPIdType ;
@ -227,4 +228,5 @@ typedef t_RsGenericIdType< PGP_KEY_FINGERPRINT_SIZE, true, RS_GENERIC_ID_PGP_F
typedef t_RsGenericIdType< CERT_SIGN_LEN , false, RS_GENERIC_ID_GXS_GROUP_ID_TYPE > GXSGroupId ;
typedef t_RsGenericIdType< CERT_SIGN_LEN , false, RS_GENERIC_ID_GXS_ID_TYPE > GXSId ;
typedef t_RsGenericIdType< CERT_SIGN_LEN , false, RS_GENERIC_ID_GXS_CIRCLE_ID_TYPE > GXSCircleId ;
typedef t_RsGenericIdType< SSL_ID_SIZE , false, RS_GENERIC_ID_GXS_TUNNEL_ID_TYPE > GXSTunnelId ;