turtle tunnel management

git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@1289 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
csoler 2009-06-03 18:47:14 +00:00
parent 2bd3899c05
commit 48218e98cb
14 changed files with 351 additions and 99 deletions

View File

@ -119,7 +119,32 @@ void ftController::addFileSource(const std::string& hash,const std::string& peer
std::cerr << "... not added: hash not found." << std::endl ; std::cerr << "... not added: hash not found." << std::endl ;
#endif #endif
} }
void ftController::removeFileSource(const std::string& hash,const std::string& peer_id)
{
RsStackMutex stack(ctrlMutex); /******* LOCKED ********/
std::map<std::string, ftFileControl>::iterator it;
std::map<std::string, ftFileControl> currentDownloads = *(&mDownloads);
#ifdef CONTROL_DEBUG
std::cerr << "ftController: Adding source " << peer_id << " to current download hash=" << hash ;
#endif
for(it = currentDownloads.begin(); it != currentDownloads.end(); it++)
if(it->first == hash)
{
it->second.mTransfer->removeFileSource(peer_id);
// setPeerState(it->second.mTransfer, peer_id, rate, mConnMgr->isOnline(peer_id));
#ifdef CONTROL_DEBUG
std::cerr << "... added." << std::endl ;
#endif
return ;
}
#ifdef CONTROL_DEBUG
std::cerr << "... not added: hash not found." << std::endl ;
#endif
}
void ftController::run() void ftController::run()
{ {

View File

@ -162,6 +162,7 @@ virtual bool CancelCacheFile(RsPeerId id, std::string path, std::string hash, ui
public: public:
virtual void statusChange(const std::list<pqipeer> &plist); virtual void statusChange(const std::list<pqipeer> &plist);
void addFileSource(const std::string& hash,const std::string& peer_id) ; void addFileSource(const std::string& hash,const std::string& peer_id) ;
void removeFileSource(const std::string& hash,const std::string& peer_id) ;
/* p3Config Interface */ /* p3Config Interface */

View File

@ -151,6 +151,27 @@ bool ftTransferModule::addFileSource(std::string peerId)
return true; return true;
} }
bool ftTransferModule::removeFileSource(std::string peerId)
{
RsStackMutex stack(tfMtx); /******* STACK LOCKED ******/
std::map<std::string,peerInfo>::iterator mit;
mit = mFileSources.find(peerId);
if (mit != mFileSources.end())
{
/* add in new source */
mFileSources.erase(mit) ;
#ifdef FT_DEBUG
std::cerr << "ftTransferModule::addFileSource(): removing peer: " << peerId << " from sourceList" << std::cerr << std::endl;
#endif
}
#ifdef FT_DEBUG
else
std::cerr << "ftTransferModule::addFileSource(): Should remove peer: " << peerId << ", but it's not in the source list. " << std::cerr << std::endl;
#endif
return true;
}
bool ftTransferModule::setPeerState(std::string peerId,uint32_t state,uint32_t maxRate) bool ftTransferModule::setPeerState(std::string peerId,uint32_t state,uint32_t maxRate)
{ {

View File

@ -131,6 +131,7 @@ public:
//interface to download controller //interface to download controller
bool setFileSources(std::list<std::string> peerIds); bool setFileSources(std::list<std::string> peerIds);
bool addFileSource(std::string peerId); bool addFileSource(std::string peerId);
bool removeFileSource(std::string peerId);
bool setPeerState(std::string peerId,uint32_t state,uint32_t maxRate); //state = ONLINE/OFFLINE bool setPeerState(std::string peerId,uint32_t state,uint32_t maxRate); //state = ONLINE/OFFLINE
bool getFileSources(std::list<std::string> &peerIds); bool getFileSources(std::list<std::string> &peerIds);
bool getPeerState(std::string peerId,uint32_t &state,uint32_t &tfRate); bool getPeerState(std::string peerId,uint32_t &state,uint32_t &tfRate);

View File

@ -69,6 +69,9 @@ const uint32_t CONFIG_TYPE_FT_SHARED = 0x0007;
const uint32_t CONFIG_TYPE_FT_EXTRA_LIST= 0x0008; const uint32_t CONFIG_TYPE_FT_EXTRA_LIST= 0x0008;
const uint32_t CONFIG_TYPE_FT_CONTROL = 0x0009; const uint32_t CONFIG_TYPE_FT_CONTROL = 0x0009;
/* turtle router */
const uint32_t CONFIG_TYPE_TURTLE = 0x0020;
/* wish these ids where higher... /* wish these ids where higher...
* may move when switch to v0.5 * may move when switch to v0.5
*/ */

View File

@ -67,11 +67,18 @@ class RsTurtle
// //
virtual TurtleRequestId turtleSearch(const std::string& match_string) = 0 ; virtual TurtleRequestId turtleSearch(const std::string& match_string) = 0 ;
// Launches a complete download file operation: diggs one or more // Initiates tunnel handling for the given file hash. tunnels. Launches
// tunnels. Launches an exception if an error occurs during the // an exception if an error occurs during the initialization process. The
// initialization process. // turtle router itself does not initiate downloads, it only maintains
// tunnels for the given hash. The download should be driven by the file
// transfer module by calling ftServer::FileRequest().
// //
virtual void turtleDownload(const std::string& name,const std::string& file_hash,uint64_t size) = 0 ; virtual void monitorFileTunnels(const std::string& name,const std::string& file_hash,uint64_t size) = 0 ;
// Tells the turtle router to stop handling tunnels for the given file hash. Traditionally this should
// be called after calling ftServer::fileCancel().
//
virtual void stopMonitoringFileTunnels(const std::string& file_hash) = 0 ;
// Sets the file sharing strategy. It concerns all local files. It would // Sets the file sharing strategy. It concerns all local files. It would
// be better to handle this for each file, of course. // be better to handle this for each file, of course.

View File

@ -813,6 +813,7 @@ int RsServer::StartupRetroShare()
mConfigMgr->addConfiguration("ranklink.cfg", mRanking); mConfigMgr->addConfiguration("ranklink.cfg", mRanking);
mConfigMgr->addConfiguration("forums.cfg", mForums); mConfigMgr->addConfiguration("forums.cfg", mForums);
mConfigMgr->addConfiguration("channels.cfg", mChannels); mConfigMgr->addConfiguration("channels.cfg", mChannels);
mConfigMgr->addConfiguration("turtle.cfg", tr);
#ifndef RS_RELEASE #ifndef RS_RELEASE
#else #else

View File

@ -53,17 +53,20 @@
#include "util/rsdebug.h" #include "util/rsdebug.h"
#include "util/rsprint.h" #include "util/rsprint.h"
// Operating System specific includes.
#include "pqi/pqinetwork.h" #include "pqi/pqinetwork.h"
static const unsigned int TUNNEL_REQUESTS_LIFE_TIME = 120 ; // life time for requests in the cache. // These number may be quite important. I setup them with sensible values, but
static const unsigned int SEARCH_REQUESTS_LIFE_TIME = 120 ; // an in-depth test would be better to get an idea of what the ideal values
// could ever be.
/* TURTLE FLAGS */ //
static const time_t TUNNEL_REQUESTS_LIFE_TIME = 120 ; /// life time for tunnel requests in the cache.
static const time_t SEARCH_REQUESTS_LIFE_TIME = 120 ; /// life time for search requests in the cache
static const time_t REGULAR_TUNNEL_DIGGING_TIME = 300 ; /// maximum interval between two tunnel digging campaigns.
static const time_t MAXIMUM_TUNNEL_IDLE_TIME = 600 ; /// maximum life time of an unused tunnel.
static const time_t MAXIMUM_HASH_IDLE_TIME = 300 ; /// maximum life time of an unused file hash.
p3turtle::p3turtle(p3ConnectMgr *cm,ftServer *fs) p3turtle::p3turtle(p3ConnectMgr *cm,ftServer *fs)
:p3Service(RS_SERVICE_TYPE_TURTLE), mConnMgr(cm) :p3Service(RS_SERVICE_TYPE_TURTLE), mConnMgr(cm), p3Config(CONFIG_TYPE_TURTLE)
{ {
RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/
@ -79,19 +82,28 @@ p3turtle::p3turtle(p3ConnectMgr *cm,ftServer *fs)
int p3turtle::tick() int p3turtle::tick()
{ {
// Handle tunnel trafic
//
handleIncoming(); // handle incoming packets handleIncoming(); // handle incoming packets
time_t now = time(NULL) ; time_t now = time(NULL) ;
// Manage tunnels every 10 sec. // Tunnel management:
// - we digg new tunnels at least every 5 min (300 sec).
// - we digg new tunnels each time a new peer connects
// - we digg new tunnels each time a new hash is asked for
// //
if(now > 10+_last_tunnel_management_time) if(now > REGULAR_TUNNEL_DIGGING_TIME+_last_tunnel_management_time || _force_digg_new_tunnels)
{ {
#ifdef P3TURTLE_DEBUG #ifdef P3TURTLE_DEBUG
std::cerr << "Calling tunnel management." << std::endl ; std::cerr << "Calling tunnel management." << std::endl ;
#endif #endif
manageTunnels() ; manageTunnels() ;
RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/
_last_tunnel_management_time = now ; _last_tunnel_management_time = now ;
_force_digg_new_tunnels = false ;
} }
// Clean every 10 sec. // Clean every 10 sec.
@ -101,12 +113,12 @@ int p3turtle::tick()
#ifdef P3TURTLE_DEBUG #ifdef P3TURTLE_DEBUG
std::cerr << "Calling autowash." << std::endl ; std::cerr << "Calling autowash." << std::endl ;
#endif #endif
autoWash() ; // clean old/unused tunnels and search requests. autoWash() ; // clean old/unused tunnels and file hashes, as well as search and tunnel requests.
_last_clean_time = now ; _last_clean_time = now ;
} }
#ifdef P3TURTLE_DEBUG #ifdef P3TURTLE_DEBUG
// Dump state every 20 sec. // Dump state for debugging, every 20 sec.
// //
static time_t last_dump = time(NULL) ; static time_t last_dump = time(NULL) ;
@ -132,38 +144,27 @@ void p3turtle::statusChange(const std::list<pqipeer> &plist) // derived from pqi
{ {
RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/
// Do we shutdown tunnels whne peers are down, or automatically find a new tunnel ? // We actually do not shut down tunnels when peers get down: Tunnels that
// I'll see that later... // are not working properly get automatically removed after some time.
// save the list of active peers. This is useful for notifying the ftContoller // save the list of active peers. This is useful for notifying the ftContoller
_online_peers = plist ; _online_peers = plist ;
std::cerr << "p3turtle: status change triggered. Saving list of " << plist.size() << " peers." << std::endl ; std::cerr << "p3turtle: status change triggered. Saving list of " << plist.size() << " peers." << std::endl ;
#ifdef TO_DO
/* get a list of all online peers */
std::list<std::string> onlineIds;
mConnMgr->getOnlineList(onlineIds);
std::list<pqipeer>::const_iterator pit; /* if any have switched to 'connected' then we force digging new tunnels */
/* if any have switched to 'connected' then we notify */
for(pit = plist.begin(); pit != plist.end(); pit++) for(std::list<pqipeer>::const_iterator pit = plist.begin(); pit != plist.end(); pit++)
{ if ((pit->state & RS_PEER_S_FRIEND) && (pit->actions & RS_PEER_CONNECTED))
if ((pit->state & RS_PEER_S_FRIEND) && _force_digg_new_tunnels = true ;
(pit->actions & RS_PEER_CONNECTED))
{
/* send our details to them */
sendOwnDetails(pit->id);
}
}
#endif
} }
// adds a virtual peer to the list that is communicated ot ftController. // adds a virtual peer to the list that is communicated ot ftController.
// //
void p3turtle::addDistantPeer(const TurtleFileHash& hash,TurtleTunnelId tid) void p3turtle::addDistantPeer(const TurtleFileHash&,TurtleTunnelId tid)
{ {
char buff[400] ; char buff[400] ;
sprintf(buff,"%s_%8x",hash.c_str(),tid) ; sprintf(buff,"Turtle tunnel %8x",tid) ;
{ {
_virtual_peers[TurtleVirtualPeerId(buff)] = tid ; _virtual_peers[TurtleVirtualPeerId(buff)] = tid ;
@ -198,21 +199,20 @@ void p3turtle::getVirtualPeersList(std::list<pqipeer>& list)
// //
void p3turtle::manageTunnels() void p3turtle::manageTunnels()
{ {
// Digg new tunnels for waiting file hashes // Digg new tunnels for all file hashes
std::vector<std::string> hashes_to_digg ; std::vector<TurtleFileHash> hashes_to_digg ;
{ {
RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/
for(std::map<TurtleFileHash,TurtleFileHashInfo>::const_iterator it(_incoming_file_hashes.begin());it!=_incoming_file_hashes.end();++it) for(std::map<TurtleFileHash,TurtleFileHashInfo>::const_iterator it(_incoming_file_hashes.begin());it!=_incoming_file_hashes.end();++it)
if(it->second.tunnels.empty()) {
{
#ifdef P3TURTLE_DEBUG #ifdef P3TURTLE_DEBUG
std::cerr << "Tunnel management: No tunnels for hash " << it->first << ", digging new ones." << std::endl ; std::cerr << "Tunnel management: digging new tunnels for hash " << it->first << "." << std::endl ;
#endif #endif
hashes_to_digg.push_back(it->first) ; hashes_to_digg.push_back(it->first) ;
} }
} }
for(uint i=0;i<hashes_to_digg.size();++i) for(uint i=0;i<hashes_to_digg.size();++i)
@ -221,8 +221,6 @@ void p3turtle::manageTunnels()
void p3turtle::autoWash() void p3turtle::autoWash()
{ {
RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/
#ifdef P3TURTLE_DEBUG #ifdef P3TURTLE_DEBUG
std::cerr << " In autowash." << std::endl ; std::cerr << " In autowash." << std::endl ;
#endif #endif
@ -231,25 +229,157 @@ void p3turtle::autoWash()
time_t now = time(NULL) ; time_t now = time(NULL) ;
for(std::map<TurtleSearchRequestId,TurtleRequestInfo>::iterator it(_search_requests_origins.begin());it!=_search_requests_origins.end();++it) // Search requests
if(now > (time_t)(it->second.time_stamp + SEARCH_REQUESTS_LIFE_TIME)) //
{ {
#ifdef P3TURTLE_DEBUG RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/
std::cerr << " removed search request " << (void *)it->first << ", timeout." << std::endl ;
#endif
_search_requests_origins.erase(it) ;
}
for(std::map<TurtleTunnelRequestId,TurtleRequestInfo>::iterator it(_tunnel_requests_origins.begin());it!=_tunnel_requests_origins.end();++it) for(std::map<TurtleSearchRequestId,TurtleRequestInfo>::iterator it(_search_requests_origins.begin());it!=_search_requests_origins.end();++it)
if(now > (time_t)(it->second.time_stamp + TUNNEL_REQUESTS_LIFE_TIME)) if(now > (time_t)(it->second.time_stamp + SEARCH_REQUESTS_LIFE_TIME))
{ {
#ifdef P3TURTLE_DEBUG #ifdef P3TURTLE_DEBUG
std::cerr << " removed tunnel request " << (void *)it->first << ", timeout." << std::endl ; std::cerr << " removed search request " << (void *)it->first << ", timeout." << std::endl ;
#endif #endif
_tunnel_requests_origins.erase(it) ; _search_requests_origins.erase(it) ;
} }
}
// Tunnel requests
//
{
RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/
for(std::map<TurtleTunnelRequestId,TurtleRequestInfo>::iterator it(_tunnel_requests_origins.begin());it!=_tunnel_requests_origins.end();++it)
if(now > (time_t)(it->second.time_stamp + TUNNEL_REQUESTS_LIFE_TIME))
{
#ifdef P3TURTLE_DEBUG
std::cerr << " removed tunnel request " << (void *)it->first << ", timeout." << std::endl ;
#endif
_tunnel_requests_origins.erase(it) ;
}
}
// Tunnels.
std::vector<TurtleTunnelId> tunnels_to_close ;
{
RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/
for(std::map<TurtleTunnelId,TurtleTunnel>::iterator it(_local_tunnels.begin());it!=_local_tunnels.end();++it)
if(now > (time_t)(it->second.time_stamp + MAXIMUM_TUNNEL_IDLE_TIME))
{
#ifdef P3TURTLE_DEBUG
std::cerr << " removing tunnel " << (void *)it->first << ": timeout." << std::endl ;
#endif
tunnels_to_close.push_back(it->first) ;
}
}
for(uint i=0;i<tunnels_to_close.size();++i)
closeTunnel(tunnels_to_close[i]) ;
// File hashes can only be removed by calling the 'stopMonitoringFileTunnels()' command.
} }
void p3turtle::closeTunnel(TurtleTunnelId tid)
{
// This is closing a given tunnel, removing it from file sources, and from the list of tunnels of its
// corresponding file hash. In the original turtle4privacy paradigm, they also send back and forward
// tunnel closing commands. I'm not sure this is necessary, because if a tunnel is closed somewhere, it's
// source is not going to be used and the tunnel will eventually disappear.
//
RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/
std::map<TurtleTunnelId,TurtleTunnel>::iterator it(_local_tunnels.find(tid)) ;
if(it == _local_tunnels.end())
{
std::cerr << "p3turtle: was asked to close tunnel 0x" << (void*)tid << ", which actually doesn't exist." << std::endl ;
return ;
}
std::cerr << "p3turtle: Closing tunnel 0x" << (void*)tid << std::endl ;
if(it->second.local_src == mConnMgr->getOwnId()) // this is a starting tunnel. We thus remove
// - the virtual peer from the vpid list
// - the tunnel id from the file hash
// - the virtual peer from the file sources in the file transfer controller.
{
TurtleTunnelId tid = it->first ;
TurtleVirtualPeerId vpid = it->second.vpid ;
TurtleFileHash hash = it->second.hash ;
#ifdef P3TURTLE_DEBUG
std::cerr << " Tunnel is a starting point. Also removing " ;
std::cerr << " Virtual Peer Id " << vpid << std::endl ;
std::cerr << " Associated file source." << std::endl ;
#endif
_ft_controller->removeFileSource(hash,vpid) ;
_virtual_peers.erase(_virtual_peers.find(vpid)) ;
std::vector<TurtleTunnelId>& tunnels(_incoming_file_hashes[hash].tunnels) ;
for(uint i=0;i<tunnels.size();++i)
if(tunnels[i] == tid)
{
tunnels[i] = tunnels.back() ;
tunnels.pop_back() ;
break ;
}
}
else if(it->second.local_dst == mConnMgr->getOwnId()) // This is a ending tunnel. We also remove the virtual peer id
{
#ifdef P3TURTLE_DEBUG
std::cerr << " Tunnel is a ending point. Also removing associated outgoing hash." ;
#endif
_outgoing_file_hashes.erase(_outgoing_file_hashes.find(it->second.hash)) ;
}
_local_tunnels.erase(it) ;
}
void p3turtle::stopMonitoringFileTunnels(const std::string& hash)
{
RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/
std::map<TurtleFileHash,TurtleFileHashInfo>::iterator it(_incoming_file_hashes.find(hash)) ;
if(it == _incoming_file_hashes.end())
{
std::cerr << "p3turtle: asked to stop monitoring file hash " << hash << ", but this hash is actually not handled by the turtle router." << std::endl ;
return ;
}
// copy the list of tunnels to remove.
std::vector<TurtleTunnelId> tunnels_to_remove = it->second.tunnels ;
#ifdef P3TURTLE_DEBUG
std::cerr << "p3turtle: stopping monitoring for file hash " << hash << ", and closing " << tunnels_to_remove.size() << " tunnels." << std::endl ;
#endif
for(uint i=0;i<tunnels_to_remove.size();++i)
closeTunnel(tunnels_to_remove[i]) ;
_incoming_file_hashes.erase(it) ;
}
// -----------------------------------------------------------------------------------//
// -------------------------------- Config functions ------------------------------ //
// -----------------------------------------------------------------------------------//
//
RsSerialiser *p3turtle::setupSerialiser()
{
RsSerialiser *rss = new RsSerialiser();
return rss ;
}
std::list<RsItem*> p3turtle::saveList(bool& cleanup)
{
cleanup = true ;
return std::list<RsItem*>() ;
}
bool p3turtle::loadList(std::list<RsItem*> load)
{
return true ;
}
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
// -------------------------------- Helper functions ------------------------------ // // -------------------------------- Helper functions ------------------------------ //
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
@ -481,6 +611,7 @@ void p3turtle::handleSearchResult(RsTurtleSearchResultItem *item)
// normally here, we should setup the forward adress, so that the owner's of the files found can be further reached by a tunnel. // normally here, we should setup the forward adress, so that the owner's of the files found can be further reached by a tunnel.
fwd_item->PeerId(it->second.origin) ; fwd_item->PeerId(it->second.origin) ;
fwd_item->depth = 2 + (rand() % 256) ; // obfuscate the depth for non immediate friends.
sendItem(fwd_item) ; sendItem(fwd_item) ;
} }
@ -638,6 +769,8 @@ void p3turtle::sendDataRequest(const std::string& peerId, const std::string& has
TurtleTunnelId tunnel_id = it->second ; TurtleTunnelId tunnel_id = it->second ;
TurtleTunnel& tunnel(_local_tunnels[tunnel_id]) ; TurtleTunnel& tunnel(_local_tunnels[tunnel_id]) ;
tunnel.time_stamp = time(NULL) ;
#ifdef P3TURTLE_DEBUG #ifdef P3TURTLE_DEBUG
assert(hash == tunnel.hash) ; assert(hash == tunnel.hash) ;
#endif #endif
@ -669,11 +802,12 @@ void p3turtle::sendFileData(const std::string& peerId, const std::string& hash,
TurtleTunnelId tunnel_id = it->second ; TurtleTunnelId tunnel_id = it->second ;
TurtleTunnel& tunnel(_local_tunnels[tunnel_id]) ; TurtleTunnel& tunnel(_local_tunnels[tunnel_id]) ;
tunnel.time_stamp = time(NULL) ;
#ifdef P3TURTLE_DEBUG #ifdef P3TURTLE_DEBUG
assert(hash == tunnel.hash) ; assert(hash == tunnel.hash) ;
#endif #endif
RsTurtleFileDataItem *item = new RsTurtleFileDataItem ; RsTurtleFileDataItem *item = new RsTurtleFileDataItem ;
item->tunnel_id = tunnel_id ; // we should randomly select a tunnel, or something more clever. item->tunnel_id = tunnel_id ;
item->chunk_offset = offset ; item->chunk_offset = offset ;
item->chunk_size = chunksize ; item->chunk_size = chunksize ;
item->chunk_data = malloc(chunksize) ; item->chunk_data = malloc(chunksize) ;
@ -747,17 +881,12 @@ std::string p3turtle::getTurtlePeerId(TurtleTunnelId tid) const
std::map<TurtleTunnelId,TurtleTunnel>::const_iterator it( _local_tunnels.find(tid) ) ; std::map<TurtleTunnelId,TurtleTunnel>::const_iterator it( _local_tunnels.find(tid) ) ;
#ifdef P3TURTLE_DEBUG
assert(it!=_local_tunnels.end()) ; assert(it!=_local_tunnels.end()) ;
assert(it->second.vpid != "") ; assert(it->second.vpid != "") ;
#endif
return it->second.vpid ; return it->second.vpid ;
// static std::string s="Turtle peer" ;
// unsigned char buf[100] ;
//
// sprintf(buff,"% 8d",id) ;
//
// return s+" "+buff;
} }
bool p3turtle::isOnline(const std::string& peer_id) const bool p3turtle::isOnline(const std::string& peer_id) const
@ -953,7 +1082,7 @@ void p3turtle::handleTunnelResult(RsTurtleTunnelOkItem *item)
// store tunnel info. // store tunnel info.
if(_local_tunnels.find(item->tunnel_id) != _local_tunnels.end()) if(_local_tunnels.find(item->tunnel_id) != _local_tunnels.end())
std::cerr << "Tunnel already there. This is an error !!" << std::endl ; std::cerr << "Tunnel id " << item->tunnel_id << " is already there. Giving up !!" << std::endl ;
TurtleTunnel& tunnel(_local_tunnels[item->tunnel_id]) ; TurtleTunnel& tunnel(_local_tunnels[item->tunnel_id]) ;
@ -1086,8 +1215,7 @@ TurtleRequestId p3turtle::turtleSearch(const std::string& string_to_match)
return id ; return id ;
} }
void p3turtle::monitorFileTunnels(const std::string& name,const std::string& file_hash,uint64_t size)
void p3turtle::turtleDownload(const std::string& name,const std::string& file_hash,uint64_t size)
{ {
{ {
RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/
@ -1106,18 +1234,24 @@ void p3turtle::turtleDownload(const std::string& name,const std::string& file_ha
// No tunnels at start, but this triggers digging new tunnels. // No tunnels at start, but this triggers digging new tunnels.
// //
_incoming_file_hashes[file_hash].tunnels.clear(); _incoming_file_hashes[file_hash].tunnels.clear();
_force_digg_new_tunnels = true ;
// also should send associated request to the file transfer module. // also should send associated request to the file transfer module.
_incoming_file_hashes[file_hash].size = size ; _incoming_file_hashes[file_hash].size = size ;
_incoming_file_hashes[file_hash].name = name ; _incoming_file_hashes[file_hash].name = name ;
_incoming_file_hashes[file_hash].time_stamp = time(NULL) ;
} }
#ifdef TO_REMOVE
std::list<std::string> srcIds ; std::list<std::string> srcIds ;
#ifdef P3TURTLE_DEBUG #ifdef P3TURTLE_DEBUG
std::cerr << "p3turtle: Calling ft server to handle the dl" << std::endl ; std::cerr << "p3turtle: Calling ft server to handle the dl" << std::endl ;
#endif #endif
_ft_server->FileRequest(name,file_hash, size, "", 0, srcIds) ; _ft_server->FileRequest(name,file_hash, size, "", 0, srcIds) ;
#endif
IndicateConfigChanged() ; // initiates saving of handled hashes.
} }
void p3turtle::returnSearchResult(RsTurtleSearchResultItem *item) void p3turtle::returnSearchResult(RsTurtleSearchResultItem *item)
@ -1151,26 +1285,33 @@ void p3turtle::dumpState()
std::cerr << " hash=0x" << it->first << ", name=" << it->second.name << ", size=" << it->second.size << ", tunnel ids =" ; std::cerr << " hash=0x" << it->first << ", name=" << it->second.name << ", size=" << it->second.size << ", tunnel ids =" ;
for(std::vector<TurtleTunnelId>::const_iterator it2(it->second.tunnels.begin());it2!=it->second.tunnels.end();++it2) for(std::vector<TurtleTunnelId>::const_iterator it2(it->second.tunnels.begin());it2!=it->second.tunnels.end();++it2)
std::cerr << " " << (void*)*it2 ; std::cerr << " " << (void*)*it2 ;
std::cerr << ", last_req=" << (void*)it->second.last_request << std::endl ; std::cerr << ", last_req=" << (void*)it->second.last_request << ", time_stamp = " << it->second.time_stamp << std::endl ;
} }
std::cerr << " Active outgoing file hashes: " << _outgoing_file_hashes.size() << std::endl ; std::cerr << " Active outgoing file hashes: " << _outgoing_file_hashes.size() << std::endl ;
for(std::map<TurtleFileHash,FileInfo>::const_iterator it(_outgoing_file_hashes.begin());it!=_outgoing_file_hashes.end();++it) for(std::map<TurtleFileHash,FileInfo>::const_iterator it(_outgoing_file_hashes.begin());it!=_outgoing_file_hashes.end();++it)
std::cerr << " hash=0x" << it->first << ", name=" << it->second.fname << ", size=" << it->second.size ; std::cerr << " hash=0x" << it->first << ", name=" << it->second.fname << ", size=" << it->second.size << std::endl ;
std::cerr << " Local tunnels:" << std::endl ; std::cerr << " Local tunnels:" << std::endl ;
for(std::map<TurtleTunnelId,TurtleTunnel>::const_iterator it(_local_tunnels.begin());it!=_local_tunnels.end();++it) for(std::map<TurtleTunnelId,TurtleTunnel>::const_iterator it(_local_tunnels.begin());it!=_local_tunnels.end();++it)
std::cerr << " " << (void*)it->first << ": from=" std::cerr << " " << (void*)it->first << ": from="
<< it->second.local_src << ", to=" << it->second.local_dst << it->second.local_src << ", to=" << it->second.local_dst
<< ", hash=0x" << it->second.hash << ", ts=" << it->second.time_stamp << " (" << now-it->second.time_stamp << " secs ago)" << ", hash=0x" << it->second.hash << ", ts=" << it->second.time_stamp << " (" << now-it->second.time_stamp << " secs ago)"
<< ", peer id =" << it->second.vpid << std::endl ; << ", peer id =" << it->second.vpid << ", time_stamp=" << it->second.time_stamp << std::endl ;
std::cerr << " buffered request origins: " << std::endl ; std::cerr << " buffered request origins: " << std::endl ;
std::cerr << " Search requests: " << _search_requests_origins.size() << std::endl ; std::cerr << " Search requests: " << _search_requests_origins.size() << std::endl ;
for(std::map<TurtleSearchRequestId,TurtleRequestInfo>::const_iterator it(_search_requests_origins.begin());it!=_search_requests_origins.end();++it) for(std::map<TurtleSearchRequestId,TurtleRequestInfo>::const_iterator it(_search_requests_origins.begin());it!=_search_requests_origins.end();++it)
std::cerr << " " << (void*)it->first << ": from=" << it->second.origin << ", ts=" << it->second.time_stamp << " (" << now-it->second.time_stamp << " secs ago)" << std::endl ; std::cerr << " " << (void*)it->first << ": from=" << it->second.origin
<< ", ts=" << it->second.time_stamp << " (" << now-it->second.time_stamp
<< " secs ago)" << std::endl ;
std::cerr << " Tunnel requests: " << _tunnel_requests_origins.size() << std::endl ; std::cerr << " Tunnel requests: " << _tunnel_requests_origins.size() << std::endl ;
for(std::map<TurtleTunnelRequestId,TurtleRequestInfo>::const_iterator it(_tunnel_requests_origins.begin());it!=_tunnel_requests_origins.end();++it) for(std::map<TurtleTunnelRequestId,TurtleRequestInfo>::const_iterator it(_tunnel_requests_origins.begin());it!=_tunnel_requests_origins.end();++it)
std::cerr << " " << (void*)it->first << ": from=" << it->second.origin << ", ts=" << it->second.time_stamp << " (" << now-it->second.time_stamp << " secs ago)" << std::endl ; std::cerr << " " << (void*)it->first << ": from=" << it->second.origin
<< ", ts=" << it->second.time_stamp << " (" << now-it->second.time_stamp
<< " secs ago)" << std::endl ;
std::cerr << " Virtual peers:" << std::endl ; std::cerr << " Virtual peers:" << std::endl ;
for(std::map<TurtleVirtualPeerId,TurtleTunnelId>::const_iterator it(_virtual_peers.begin());it!=_virtual_peers.end();++it) for(std::map<TurtleVirtualPeerId,TurtleTunnelId>::const_iterator it(_virtual_peers.begin());it!=_virtual_peers.end();++it)
std::cerr << " id=" << it->first << ", tunnel=" << (void*)(it->second) << std::endl ; std::cerr << " id=" << it->first << ", tunnel=" << (void*)(it->second) << std::endl ;

View File

@ -161,6 +161,7 @@ class ftServer ;
class p3AuthMgr; class p3AuthMgr;
class p3ConnectMgr; class p3ConnectMgr;
class ftDataMultiplex; class ftDataMultiplex;
class RsSerialiser;
static const int TURTLE_MAX_SEARCH_DEPTH = 6 ; static const int TURTLE_MAX_SEARCH_DEPTH = 6 ;
// This class is used to keep trace of requests (searches and tunnels). // This class is used to keep trace of requests (searches and tunnels).
@ -191,10 +192,22 @@ class TurtleFileHashInfo
TurtleRequestId last_request ; // last request for the tunnels of this hash TurtleRequestId last_request ; // last request for the tunnels of this hash
TurtleFileName name ; TurtleFileName name ;
time_t time_stamp ;
uint64_t size ; uint64_t size ;
}; };
class p3turtle: public p3Service, public pqiMonitor, public RsTurtle, public ftSearch // Subclassing:
//
// Class | Brings what | Usage
// -----------+------------------+------------------------------------------------------
// p3Service | sendItem() | handle packet sending/receiving to/from friend peers.
// pqiMonitor | configChanged() | handle who's connecting/disconnecting to dig new tunnels
// RsTurtle | start/stop file()| brings interface for turtle service
// ftSearch | search() | used to allow searching for monitored files.
// p3Config | ConfigChanged() | used to load/save .cfg file for turtle variales.
// -----------+------------------+------------------------------------------------------
//
class p3turtle: public p3Service, public pqiMonitor, public RsTurtle, public ftSearch, public p3Config
{ {
public: public:
p3turtle(p3ConnectMgr *cm,ftServer *m); p3turtle(p3ConnectMgr *cm,ftServer *m);
@ -205,16 +218,24 @@ class p3turtle: public p3Service, public pqiMonitor, public RsTurtle, public ftS
// //
virtual TurtleSearchRequestId turtleSearch(const std::string& string_to_match) ; virtual TurtleSearchRequestId turtleSearch(const std::string& string_to_match) ;
// Initiates tunnel handling for the given file hash. // Initiates tunnel handling for the given file hash. tunnels. Launches
// tunnels. Launches an exception if an error occurs during the // an exception if an error occurs during the initialization process. The
// initialization process. The turtle router itself does not initiate downloads, // turtle router itself does not initiate downloads, it only maintains
// it only maintains tunnels for the given hash. The download should be // tunnels for the given hash. The download should be driven by the file
// driven by the file transfer module. Maybe this function can do the whole thing: // transfer module. Maybe this function can do the whole thing:
// - initiate tunnel handling // - initiate tunnel handling
// - send the file request to the file transfer module // - send the file request to the file transfer module
// - populate the file transfer module with the adequate pqi interface and search module. // - populate the file transfer module with the adequate pqi interface and search module.
// //
virtual void turtleDownload(const std::string& name,const std::string& file_hash,uint64_t size) ; // This function should be called in addition to ftServer::FileRequest() so that the turtle router
// automatically provide tunnels for the file to download.
//
virtual void monitorFileTunnels(const std::string& name,const std::string& file_hash,uint64_t size) ;
// This should be called when canceling a file download, so that the turtle router stops
// handling tunnels for this file.
//
virtual void stopMonitoringFileTunnels(const std::string& file_hash) ;
/************* from pqiMonitor *******************/ /************* from pqiMonitor *******************/
// Informs the turtle router that some peers are (dis)connected. This should initiate digging new tunnels, // Informs the turtle router that some peers are (dis)connected. This should initiate digging new tunnels,
@ -237,6 +258,11 @@ class p3turtle: public p3Service, public pqiMonitor, public RsTurtle, public ftS
// //
virtual bool search(std::string hash, uint64_t size, uint32_t hintflags, FileInfo &info) const ; virtual bool search(std::string hash, uint64_t size, uint32_t hintflags, FileInfo &info) const ;
/************* from p3Config *******************/
virtual RsSerialiser *setupSerialiser() ;
virtual std::list<RsItem*> saveList(bool& cleanup) ;
virtual bool loadList(std::list<RsItem*> load) ;
/************* Communication with ftserver *******************/ /************* Communication with ftserver *******************/
// Does the turtle router manages tunnels to this peer ? (this is not a // Does the turtle router manages tunnels to this peer ? (this is not a
// real id, but a fake one, that the turtle router is capable of connecting with a tunnel id). // real id, but a fake one, that the turtle router is capable of connecting with a tunnel id).
@ -271,8 +297,9 @@ class p3turtle: public p3Service, public pqiMonitor, public RsTurtle, public ftS
//----------------------------- Routing functions ----------------------------// //----------------------------- Routing functions ----------------------------//
void manageTunnels() ; /// Handle tunnel digging for current file hashes void manageTunnels() ; /// Handle tunnel digging for current file hashes
int handleIncoming(); /// Main routing function void closeTunnel(TurtleTunnelId tid) ; /// closes a given tunnel
int handleIncoming(); /// Main routing function
void handleSearchRequest(RsTurtleSearchRequestItem *item); /// specific routing functions for handling particular packets. void handleSearchRequest(RsTurtleSearchRequestItem *item); /// specific routing functions for handling particular packets.
void handleSearchResult(RsTurtleSearchResultItem *item); void handleSearchResult(RsTurtleSearchResultItem *item);
@ -303,18 +330,16 @@ class p3turtle: public p3Service, public pqiMonitor, public RsTurtle, public ftS
std::map<TurtleSearchRequestId,TurtleRequestInfo> _search_requests_origins ; /// keeps trace of who emmitted a given search request std::map<TurtleSearchRequestId,TurtleRequestInfo> _search_requests_origins ; /// keeps trace of who emmitted a given search request
std::map<TurtleTunnelRequestId,TurtleRequestInfo> _tunnel_requests_origins ; /// keeps trace of who emmitted a tunnel request std::map<TurtleTunnelRequestId,TurtleRequestInfo> _tunnel_requests_origins ; /// keeps trace of who emmitted a tunnel request
std::map<TurtleFileHash,TurtleFileHashInfo> _incoming_file_hashes ; /// stores adequate tunnels for each file hash locally managed std::map<TurtleFileHash,TurtleFileHashInfo> _incoming_file_hashes ; /// stores adequate tunnels for each file hash locally managed
std::map<TurtleFileHash,FileInfo> _outgoing_file_hashes ; /// stores file info for each file we provide. std::map<TurtleFileHash,FileInfo> _outgoing_file_hashes ; /// stores file info for each file we provide.
std::map<TurtleTunnelId,TurtleTunnel > _local_tunnels ; /// local tunnels, stored by ids (Either transiting or ending). std::map<TurtleTunnelId,TurtleTunnel > _local_tunnels ; /// local tunnels, stored by ids (Either transiting or ending).
std::map<TurtleVirtualPeerId,TurtleTunnelId> _virtual_peers ; /// Peers corresponding to each tunnel. std::map<TurtleVirtualPeerId,TurtleTunnelId> _virtual_peers ; /// Peers corresponding to each tunnel.
time_t _last_clean_time ; time_t _last_clean_time ;
time_t _last_tunnel_management_time ; time_t _last_tunnel_management_time ;
std::list<pqipeer> _online_peers; std::list<pqipeer> _online_peers;
bool _force_digg_new_tunnels ; /// used to force digging new tunnels
#ifdef P3TURTLE_DEBUG #ifdef P3TURTLE_DEBUG
void dumpState() ; void dumpState() ;
#endif #endif

View File

@ -33,11 +33,12 @@ class RsTurtleSearchResultItem: public RsTurtleItem
RsTurtleSearchResultItem() : RsTurtleItem(RS_TURTLE_SUBTYPE_SEARCH_RESULT) {} RsTurtleSearchResultItem() : RsTurtleItem(RS_TURTLE_SUBTYPE_SEARCH_RESULT) {}
RsTurtleSearchResultItem(void *data,uint32_t size) ; // deserialization RsTurtleSearchResultItem(void *data,uint32_t size) ; // deserialization
uint16_t depth ; TurtleSearchRequestId request_id ; // Randomly generated request id.
uint8_t peer_id[16]; // peer id. This will eventually be obfuscated in some way.
TurtleSearchRequestId request_id ; // randomly generated request id.
uint16_t depth ; // The depth of a search result is obfuscated in this way:
// If the actual depth is 1, this field will be 1.
// If the actual depth is > 1, this field is a larger arbitrary integer.
std::list<TurtleFileInfo> result ; std::list<TurtleFileInfo> result ;
virtual std::ostream& print(std::ostream& o, uint16_t) ; virtual std::ostream& print(std::ostream& o, uint16_t) ;

View File

@ -611,9 +611,9 @@ void TransfersDialog::insertTransfers()
int dlPeers = 0; int dlPeers = 0;
for (pit = info.peers.begin(); pit != info.peers.end(); pit++) { for (pit = info.peers.begin(); pit != info.peers.end(); pit++) {
symbol = ""; symbol = "";
name = QString::fromStdString(rsPeers->getPeerName(pit->peerId)); name = getPeerName(pit->peerId);
//unique combination: fileName + peerName, variant: hash + peerName (too long) //unique combination: fileName + peerName, variant: hash + peerName (too long)
coreId = QString::fromStdString(info.fname + rsPeers->getPeerName(pit->peerId)); coreId = QString::fromStdString(info.fname) + getPeerName(pit->peerId);
fileSize = info.size; fileSize = info.size;
progress = (info.transfered * 100.0) / info.size; progress = (info.transfered * 100.0) / info.size;
dlspeed = pit->tfRate * 1024.0; dlspeed = pit->tfRate * 1024.0;
@ -645,7 +645,7 @@ void TransfersDialog::insertTransfers()
continue; continue;
/* if peers found in selectedIds, select again */ /* if peers found in selectedIds, select again */
if (selectedIds.end() != std::find(selectedIds.begin(), selectedIds.end(), info.fname + rsPeers->getPeerName(pit->peerId))) { if (selectedIds.end() != std::find(selectedIds.begin(), selectedIds.end(), info.fname + getPeerName(pit->peerId).toStdString())) {
QStandardItem *dlItem = DLListModel->item(addedRow); QStandardItem *dlItem = DLListModel->item(addedRow);
QModelIndex childIndex = DLListModel->indexFromItem(dlItem).child(dlPeers, 0); QModelIndex childIndex = DLListModel->indexFromItem(dlItem).child(dlPeers, 0);
selection->select(childIndex, QItemSelectionModel::Rows | QItemSelectionModel::SelectCurrent); selection->select(childIndex, QItemSelectionModel::Rows | QItemSelectionModel::SelectCurrent);
@ -669,7 +669,7 @@ void TransfersDialog::insertTransfers()
symbol = ""; symbol = "";
coreId = QString::fromStdString(info.hash); coreId = QString::fromStdString(info.hash);
name = QString::fromStdString(info.fname); name = QString::fromStdString(info.fname);
sources = QString::fromStdString(rsPeers->getPeerName(pit->peerId)); sources = getPeerName(pit->peerId);
switch(pit->status) switch(pit->status)
{ {
@ -749,6 +749,19 @@ void TransfersDialog::insertTransfers()
} }
} }
QString TransfersDialog::getPeerName(const std::string& id) const
{
QString res = QString::fromStdString(rsPeers->getPeerName(id)) ;
// This is because turtle tunnels have no name (I didn't want to bother with
// connect mgr). In such a case their id can suitably hold for a name.
//
if(res == "")
return QString::fromStdString(id) ;
else
return res ;
}
void TransfersDialog::cancel() void TransfersDialog::cancel()
{ {
QString queryWrn2; QString queryWrn2;
@ -764,11 +777,13 @@ void TransfersDialog::cancel()
if(selection->isRowSelected(i, QModelIndex())) if(selection->isRowSelected(i, QModelIndex()))
{ {
std::string id = getID(i, DLListModel).toStdString(); std::string id = getID(i, DLListModel).toStdString();
#ifdef UNUSED
QString qname = getFileName(i, DLListModel); QString qname = getFileName(i, DLListModel);
/* XXX -> Should not have to 'trim' filename ... something wrong here.. /* XXX -> Should not have to 'trim' filename ... something wrong here..
* but otherwise, not exact filename .... BUG * but otherwise, not exact filename .... BUG
*/ */
std::string name = (qname.trimmed()).toStdString(); std::string name = (qname.trimmed()).toStdString();
#endif
rsFiles->FileCancel(id); /* hash */ rsFiles->FileCancel(id); /* hash */
} }

View File

@ -74,6 +74,8 @@ class TransfersDialog : public MainPage
void playFiles(QStringList files); void playFiles(QStringList files);
private: private:
QString getPeerName(const std::string& peer_id) const ;
QStandardItemModel *DLListModel; QStandardItemModel *DLListModel;
QStandardItemModel *ULListModel; QStandardItemModel *ULListModel;
QItemSelectionModel *selection; QItemSelectionModel *selection;

View File

@ -259,12 +259,14 @@ void TurtleSearchDialog::download()
"", 0, srcIds); "", 0, srcIds);
#endif #endif
std::list<std::string> srcIds;
std::cout << "Issuing file request from search dialog: -" std::cout << "Issuing file request from search dialog: -"
<< (item->text(SR_NAME_COL)).toStdString() << "-" << (item->text(SR_NAME_COL)).toStdString() << "-"
<< (item->text(SR_HASH_COL)).toStdString() << "-" << (item->text(SR_HASH_COL)).toStdString() << "-"
<< (item->text(SR_REALSIZE_COL)).toInt() << std::endl ; << (item->text(SR_REALSIZE_COL)).toInt() << std::endl ;
rsTurtle->turtleDownload(item->text(SR_NAME_COL).toStdString(),item->text(SR_HASH_COL).toStdString(),item->text(SR_REALSIZE_COL).toInt()) ; rsTurtle->monitorFileTunnels(item->text(SR_NAME_COL).toStdString(),item->text(SR_HASH_COL).toStdString(),item->text(SR_REALSIZE_COL).toInt()) ;
rsFiles->FileRequest(item->text(SR_NAME_COL).toStdString(),item->text(SR_HASH_COL).toStdString(),item->text(SR_REALSIZE_COL).toInt(),"",0,srcIds) ;
} }
} }

View File

@ -67,11 +67,18 @@ class RsTurtle
// //
virtual TurtleRequestId turtleSearch(const std::string& match_string) = 0 ; virtual TurtleRequestId turtleSearch(const std::string& match_string) = 0 ;
// Launches a complete download file operation: diggs one or more // Initiates tunnel handling for the given file hash. tunnels. Launches
// tunnels. Launches an exception if an error occurs during the // an exception if an error occurs during the initialization process. The
// initialization process. // turtle router itself does not initiate downloads, it only maintains
// tunnels for the given hash. The download should be driven by the file
// transfer module by calling ftServer::FileRequest().
// //
virtual void turtleDownload(const std::string& name,const std::string& file_hash,uint64_t size) = 0 ; virtual void monitorFileTunnels(const std::string& name,const std::string& file_hash,uint64_t size) = 0 ;
// Tells the turtle router to stop handling tunnels for the given file hash. Traditionally this should
// be called after calling ftServer::fileCancel().
//
virtual void stopMonitoringFileTunnels(const std::string& file_hash) = 0 ;
// Sets the file sharing strategy. It concerns all local files. It would // Sets the file sharing strategy. It concerns all local files. It would
// be better to handle this for each file, of course. // be better to handle this for each file, of course.