2015-11-17 18:11:00 -05:00
/*
* libretroshare / src / chat : distantchat . h
*
* Services for RetroShare .
*
2015-11-22 11:36:14 -05:00
* Copyright 2015 by Cyril Soler
2015-11-17 18:11:00 -05:00
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Library General Public
* License Version 2 as published by the Free Software Foundation .
*
* This library 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
* Library General Public License for more details .
*
* You should have received a copy of the GNU Library General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307
* USA .
*
* Please report all bugs and problems to " csoler@users.sourceforge.net " .
*
*/
# pragma once
2015-11-22 11:36:14 -05:00
// Generic tunnel service
//
// Preconditions:
// * multiple services can use the same tunnel
// * tunnels are automatically encrypted and ensure transport (items stored in a queue until ACKed by the other side)
// * each tunnel is associated to a specific GXS id on both sides. Consequently, services that request tunnels from different IDs to a
// server for the same GXS id need to be handled correctly.
//
// GUI
// * the GUI should show for each tunnel:
// - starting and ending GXS ids
// - tunnel status (DH ok, closed from distant peer, locally closed, etc)
// - amount of data that is transferred in the tunnel
// - number of pending items (and total size)
// - number ACKed items both ways.
//
// we can use an additional tab "Authenticated tunnels" in the statistics->turtle window
//
// Interaction with services:
//
2015-11-30 00:02:44 -05:00
// Services request tunnels from a given GXS id and to a given GXS id. When ready, they get a handle (type = RsGxsTunnelId)
2015-11-22 11:36:14 -05:00
//
// Services send data in the tunnel using the virtual peer id
//
// 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.
2015-11-22 23:19:46 -05:00
//
// Algorithms
//
// Tunnel establishment
2015-11-23 22:19:18 -05:00
// * we need two layers: the turtle layer, and the GXS id layer.
2015-11-30 00:02:44 -05:00
// - for each pair of GXS ids talking, a single turtle tunnel is used
// - that tunnel can be shared by multiple services using it.
// - services are responsoble for asking tunnels and also droppping them when unused.
// - at the turtle layer, the tunnel will be closed only when no service uses it.
// * IDs
// TurtleVirtualPeerId:
// - Used by tunnel service for each turtle tunnel
// - one virtual peer ID per GXS tunnel
//
// GxsTunnelId:
// - one GxsTunnelId per couple of GXS ids. But we also need to allow multiple services to use the tunnel.
//
2015-11-22 23:19:46 -05:00
// * 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.
//
2015-11-23 22:19:18 -05:00
// Turtle hash: [ 0 ---------------15 16---19 ]
// Destination Source
//
// We Use 16 bytes to target the exact destination of the hash. The source part is just 4 arbitrary bytes that need to be different for all source
// IDs that come from the same peer, which is quite likely to be sufficient. The real source of the tunnel will make itself known when sending the
// DH key.
//
// Another option is to use random bytes in 16-19. But then, we would digg multiple times different tunnels between the same two peers even when requesting
// a GXS tunnel for the same pair of GXS ids. Is that a problem?
// - that solves the problem of colliding source GXS ids (since 4 bytes is too small)
// - the DH will make it clear that we're talking to the same person if it already exist.
//
2015-11-22 23:19:46 -05:00
// * 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.
//
//
2015-11-30 00:02:44 -05:00
// RequestTunnel(source_own_id,destination_id) -
// | |
// +---------------------------> p3Turtle::monitorTunnels( hash(destination_id) ) |
// | |
// [Turtle async work] -------------------+ | Turtle layer: one virtual peer id
// | | |
// handleTunnelRequest() <-----------------------------------------------+ | |
// | | |
// +---------------- keep record in _gxs_tunnel_virtual_peer_id, initiate DH exchange | -
// | |
// handleDHPublicKey() <-----------------------------------------------------------------------------+ |
// | |
// +---------------- update _gxs_tunnel_contacts[ tunnel_hash = hash(own_id, destination_id) ] | GxsTunnelId level
// | |
// +---------------- notify client service that Peer(destination_id, tunnel_hash) is ready to talk to |
// -
2015-11-22 23:19:46 -05:00
// 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.
2015-11-23 22:19:18 -05:00
// Without this, it's not possible to request two tunnels to a same server GXS id but from a different client GXS id. Indeed, if the two hashes are the same,
// from the same peer, the tunnel names will be identical and so will be the virtual peer ids, if the route is the same (because of multi-tunneling, they
// will be different if the route is different).
//
// *
2015-11-22 11:36:14 -05:00
2015-11-17 18:11:00 -05:00
# include <turtle/turtleclientservice.h>
# include <retroshare/rsgxstunnel.h>
2015-11-28 18:02:57 -05:00
# include <services/p3service.h>
2015-11-18 23:56:35 -05:00
# include <gxstunnel/rsgxstunnelitems.h>
2015-11-17 18:11:00 -05:00
class RsGixs ;
static const uint32_t GXS_TUNNEL_AES_KEY_SIZE = 16 ;
2015-11-28 18:02:57 -05:00
class p3GxsTunnelService : public RsGxsTunnelService , public RsTurtleClientService , public p3Service
2015-11-17 18:11:00 -05:00
{
public :
2015-11-24 21:57:59 -05:00
p3GxsTunnelService ( RsGixs * pids ) ;
2015-11-17 18:11:00 -05:00
virtual void connectToTurtleRouter ( p3turtle * ) ;
// 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.
//
2015-11-30 00:02:44 -05:00
virtual bool requestSecuredTunnel ( const RsGxsId & to_id , const RsGxsId & from_id , RsGxsTunnelId & tunnel_id , uint32_t service_id , uint32_t & error_code ) ;
2015-11-24 21:57:59 -05:00
2015-11-30 00:02:44 -05:00
virtual bool closeExistingTunnel ( const RsGxsTunnelId & tunnel_id , uint32_t service_id ) ;
2015-12-01 23:40:35 -05:00
virtual bool getTunnelsInfo ( std : : vector < GxsTunnelInfo > & infos ) ;
2015-11-28 14:55:56 -05:00
virtual bool getTunnelInfo ( const RsGxsTunnelId & tunnel_id , GxsTunnelInfo & info ) ;
2015-11-24 21:57:59 -05:00
virtual bool sendData ( const RsGxsTunnelId & tunnel_id , uint32_t service_id , const uint8_t * data , uint32_t size ) ;
virtual bool registerClientService ( uint32_t service_id , RsGxsTunnelClientService * service ) ;
2015-11-17 18:11:00 -05:00
2015-11-28 18:02:57 -05:00
// derived from p3service
virtual int tick ( ) ;
virtual RsServiceInfo getServiceInfo ( ) ;
2015-11-17 18:11:00 -05:00
private :
2015-11-22 11:36:14 -05:00
void flush ( ) ;
2015-11-24 21:57:59 -05:00
virtual void handleIncomingItem ( const RsGxsTunnelId & tunnel_id , RsGxsTunnelItem * ) ;
2015-11-22 11:36:14 -05:00
2015-11-17 18:11:00 -05:00
class GxsTunnelPeerInfo
{
public :
GxsTunnelPeerInfo ( ) : last_contact ( 0 ) , last_keep_alive_sent ( 0 ) , status ( 0 ) , direction ( 0 )
{
memset ( aes_key , 0 , GXS_TUNNEL_AES_KEY_SIZE ) ;
2015-12-01 23:40:35 -05:00
total_sent = 0 ;
total_received = 0 ;
2015-11-17 18:11:00 -05:00
}
time_t last_contact ; // used to keep track of working connexion
time_t last_keep_alive_sent ; // last time we sent a keep alive packet.
unsigned char aes_key [ GXS_TUNNEL_AES_KEY_SIZE ] ;
uint32_t status ; // info: do we have a tunnel ?
RsPeerId virtual_peer_id ; // given by the turtle router. Identifies the tunnel.
2015-11-23 22:19:18 -05:00
RsGxsId to_gxs_id ; // gxs id we're talking to
2015-11-17 18:11:00 -05:00
RsGxsId own_gxs_id ; // gxs id we're using to talk.
RsTurtleGenericTunnelItem : : Direction direction ; // specifiec wether we are client(managing the tunnel) or server.
2015-11-23 22:19:18 -05:00
TurtleFileHash hash ; // hash that is last used. This is necessary for handling tunnel establishment
2015-11-30 00:02:44 -05:00
std : : set < uint32_t > client_services ; // services that used this tunnel
2015-12-01 23:40:35 -05:00
uint32_t total_sent ;
uint32_t total_received ;
2015-11-17 18:11:00 -05:00
} ;
class GxsTunnelDHInfo
{
public :
GxsTunnelDHInfo ( ) : dh ( 0 ) , direction ( 0 ) , status ( 0 ) { }
DH * dh ;
RsGxsId gxs_id ;
2015-11-22 23:19:46 -05:00
RsGxsId own_gxs_id ;
2015-11-23 22:19:18 -05:00
RsGxsTunnelId tunnel_id ; // this is a proxy, since we cna always recompute that from the two previous values.
2015-11-17 18:11:00 -05:00
RsTurtleGenericTunnelItem : : Direction direction ;
uint32_t status ;
TurtleFileHash hash ;
} ;
2015-11-24 21:57:59 -05:00
struct GxsTunnelData
{
RsGxsTunnelDataItem * data_item ;
time_t last_sending_attempt ;
} ;
2015-11-17 18:11:00 -05:00
// This maps contains the current peers to talk to with distant chat.
//
2015-11-23 22:19:18 -05:00
std : : map < RsGxsTunnelId , GxsTunnelPeerInfo > _gxs_tunnel_contacts ; // current peers we can talk to
std : : map < TurtleVirtualPeerId , GxsTunnelDHInfo > _gxs_tunnel_virtual_peer_ids ; // current virtual peers. Used to figure out tunnels, etc.
2015-11-17 18:11:00 -05:00
// List of items to be sent asap. Used to store items that we cannot pass directly to
// sendTurtleData(), because of Mutex protection.
2015-11-24 21:57:59 -05:00
std : : map < uint64_t , GxsTunnelData > pendingGxsTunnelDataItems ; // items that need provable transport and encryption
std : : list < RsGxsTunnelItem * > pendingGxsTunnelItems ; // items that do not need provable transport, yet need encryption
std : : list < RsGxsTunnelDHPublicKeyItem * > pendingDHItems ;
2015-11-17 18:11:00 -05:00
// Overloaded from RsTurtleClientService
virtual bool handleTunnelRequest ( const RsFileHash & hash , const RsPeerId & peer_id ) ;
virtual void receiveTurtleData ( RsTurtleGenericTunnelItem * item , const RsFileHash & hash , const RsPeerId & virtual_peer_id , RsTurtleGenericTunnelItem : : Direction direction ) ;
void addVirtualPeer ( const TurtleFileHash & , const TurtleVirtualPeerId & , RsTurtleGenericTunnelItem : : Direction dir ) ;
void removeVirtualPeer ( const TurtleFileHash & , const TurtleVirtualPeerId & ) ;
// session handling handles
2015-11-30 00:02:44 -05:00
void startClientGxsTunnelConnection ( const RsGxsId & to_gxs_id , const RsGxsId & from_gxs_id , uint32_t service_id , RsGxsTunnelId & tunnel_id ) ;
2015-11-17 18:11:00 -05:00
void locked_restartDHSession ( const RsPeerId & virtual_peer_id , const RsGxsId & own_gxs_id ) ;
// utility functions
2015-11-23 22:19:18 -05:00
static TurtleFileHash randomHashFromDestinationGxsId ( const RsGxsId & destination ) ;
static RsGxsId destinationGxsIdFromHash ( const TurtleFileHash & sum ) ;
2015-11-17 18:11:00 -05:00
// Cryptography management
void handleRecvDHPublicKey ( RsGxsTunnelDHPublicKeyItem * item ) ;
bool locked_sendDHPublicKey ( const DH * dh , const RsGxsId & own_gxs_id , const RsPeerId & virtual_peer_id ) ;
bool locked_initDHSessionKey ( DH * & dh ) ;
2015-11-18 23:56:35 -05:00
TurtleVirtualPeerId virtualPeerIdFromHash ( const TurtleFileHash & hash ) ; // ... and to a hash for p3turtle
2015-11-22 23:19:46 -05:00
RsGxsTunnelId makeGxsTunnelId ( const RsGxsId & own_id , const RsGxsId & distant_id ) const ; // creates a unique ID from two GXS ids.
2015-11-17 18:11:00 -05:00
2015-11-22 11:36:14 -05:00
// item handling
2015-11-24 21:57:59 -05:00
void handleRecvStatusItem ( const RsGxsTunnelId & id , RsGxsTunnelStatusItem * item ) ;
void handleRecvTunnelDataItem ( const RsGxsTunnelId & id , RsGxsTunnelDataItem * item ) ;
void handleRecvTunnelDataAckItem ( const RsGxsTunnelId & id , RsGxsTunnelDataAckItem * item ) ;
2015-11-22 11:36:14 -05:00
2015-11-17 18:11:00 -05:00
// Comunication with Turtle service
2015-11-24 21:57:59 -05:00
bool locked_sendEncryptedTunnelData ( RsGxsTunnelItem * item ) ;
bool locked_sendClearTunnelData ( RsGxsTunnelDHPublicKeyItem * item ) ; // this limits the usage to DH items. Others should be encrypted!
2015-11-17 18:11:00 -05:00
bool handleEncryptedData ( const uint8_t * data_bytes , uint32_t data_size , const TurtleFileHash & hash , const RsPeerId & virtual_peer_id ) ;
// local data
p3turtle * mTurtle ;
RsGixs * mGixs ;
RsMutex mGxsTunnelMtx ;
2015-11-24 21:57:59 -05:00
uint64_t global_item_counter ;
std : : map < uint32_t , RsGxsTunnelClientService * > mRegisteredServices ;
2015-11-28 18:02:57 -05:00
void debug_dump ( ) ;
2015-11-17 18:11:00 -05:00
} ;
2015-11-24 21:57:59 -05:00