fixed merge with upstream/master

This commit is contained in:
csoler 2018-07-19 23:22:24 +02:00
commit 2bab688dec
No known key found for this signature in database
GPG key ID: 7BCA522266C0804C
99 changed files with 4868 additions and 904 deletions

View file

@ -31,6 +31,7 @@
#endif
#include "rsserver/p3face.h"
#include "crypto/rscrypto.h"
#include "pqi/authssl.h"
#include "pqi/p3linkmgr.h"
@ -60,11 +61,14 @@ static std::map<TurtleTunnelRequestId, std::vector<time_t> > TS_request_bounces
void TS_dumpState() ;
#endif
#define TURTLE_DEBUG() std::cerr << time(NULL) << " : TURTLE : " << __FUNCTION__ << " : "
#define TURTLE_ERROR() std::cerr << "(EE) TURTLE ERROR : "
// These number may be quite important. I setup them with sensible values, but
// an in-depth test would be better to get an idea of what the ideal values
// could ever be.
//
// update of 14-03-11:
// update of 14-03-11:
// - I raised the cache time for tunnel requests. This avoids inconsistencies such as:
// * tunnel requests bouncing back while the original request is not in the cache anymore
// * special case of this for own file transfer: an outgoing tunnel is built with no end.
@ -76,17 +80,18 @@ void TS_dumpState() ;
// - The total number of TR per second emmited from self will be MAX_TUNNEL_REQS_PER_SECOND / TIME_BETWEEN_TUNNEL_MANAGEMENT_CALLS = 0.5
// - I updated forward probabilities to higher values, and min them to 1/nb_connected_friends to prevent blocking tunnels.
//
static const time_t TUNNEL_REQUESTS_LIFE_TIME = 240 ; /// life time for tunnel requests in the cache.
static const time_t SEARCH_REQUESTS_LIFE_TIME = 240 ; /// 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 = 60 ; /// maximum life time of an unused tunnel.
static const time_t EMPTY_TUNNELS_DIGGING_TIME = 50 ; /// look into tunnels regularly every 50 sec.
static const time_t TUNNEL_SPEED_ESTIMATE_LAPSE = 5 ; /// estimate tunnel speed every 5 seconds
static const time_t TUNNEL_CLEANING_LAPS_TIME = 10 ; /// clean tunnels every 10 secs
static const time_t TIME_BETWEEN_TUNNEL_MANAGEMENT_CALLS = 2 ; /// Tunnel management calls every 2 secs.
static const uint32_t MAX_TUNNEL_REQS_PER_SECOND = 1 ; /// maximum number of tunnel requests issued per second. Was 0.5 before
static const uint32_t MAX_ALLOWED_SR_IN_CACHE = 120 ; /// maximum number of search requests allowed in cache. That makes 2 per sec.
static const uint32_t TURTLE_SEARCH_RESULT_MAX_HITS =5000 ; /// maximum number of search results forwarded back to the source.
static const time_t TUNNEL_REQUESTS_LIFE_TIME = 240 ; /// life time for tunnel requests in the cache.
static const time_t SEARCH_REQUESTS_LIFE_TIME = 240 ; /// 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 = 60 ; /// maximum life time of an unused tunnel.
static const time_t EMPTY_TUNNELS_DIGGING_TIME = 50 ; /// look into tunnels regularly every 50 sec.
static const time_t TUNNEL_SPEED_ESTIMATE_LAPSE = 5 ; /// estimate tunnel speed every 5 seconds
static const time_t TUNNEL_CLEANING_LAPS_TIME = 10 ; /// clean tunnels every 10 secs
static const time_t TIME_BETWEEN_TUNNEL_MANAGEMENT_CALLS = 2 ; /// Tunnel management calls every 2 secs.
static const uint32_t MAX_TUNNEL_REQS_PER_SECOND = 1 ; /// maximum number of tunnel requests issued per second. Was 0.5 before
static const uint32_t MAX_ALLOWED_SR_IN_CACHE = 120 ; /// maximum number of search requests allowed in cache. That makes 2 per sec.
static const uint32_t TURTLE_SEARCH_RESULT_MAX_HITS_FILES =5000 ; /// maximum number of search results forwarded back to the source.
static const uint32_t TURTLE_SEARCH_RESULT_MAX_HITS_DEFAULT= 100 ; /// default maximum number of search results forwarded back source.
static const float depth_peer_probability[7] = { 1.0f,0.99f,0.9f,0.7f,0.6f,0.5,0.4f } ;
@ -148,13 +153,15 @@ void p3turtle::getItemNames(std::map<uint8_t,std::string>& names) const
{
names.clear();
names[RS_TURTLE_SUBTYPE_STRING_SEARCH_REQUEST ] = "Search request";
names[RS_TURTLE_SUBTYPE_SEARCH_RESULT ] = "Search result";
names[RS_TURTLE_SUBTYPE_STRING_SEARCH_REQUEST ] = "Filename substring search request";
names[RS_TURTLE_SUBTYPE_GENERIC_SEARCH_REQUEST ] = "Generic search request";
names[RS_TURTLE_SUBTYPE_FT_SEARCH_RESULT ] = "File search result";
names[RS_TURTLE_SUBTYPE_GENERIC_SEARCH_RESULT ] = "Generic search result";
names[RS_TURTLE_SUBTYPE_OPEN_TUNNEL ] = "Tunnel request";
names[RS_TURTLE_SUBTYPE_TUNNEL_OK ] = "Tunnel response";
names[RS_TURTLE_SUBTYPE_FILE_REQUEST ] = "Data request";
names[RS_TURTLE_SUBTYPE_FILE_DATA ] = "Data chunk";
names[RS_TURTLE_SUBTYPE_REGEXP_SEARCH_REQUEST ] = "RegExp search";
names[RS_TURTLE_SUBTYPE_REGEXP_SEARCH_REQUEST ] = "Filename RegExp search request";
names[RS_TURTLE_SUBTYPE_GENERIC_DATA ] = "Generic data";
names[RS_TURTLE_SUBTYPE_FILE_MAP ] = "Chunk map";
names[RS_TURTLE_SUBTYPE_FILE_MAP_REQUEST ] = "Chunk map request";
@ -162,7 +169,7 @@ void p3turtle::getItemNames(std::map<uint8_t,std::string>& names) const
names[RS_TURTLE_SUBTYPE_CHUNK_CRC_REQUEST ] = "Chunk CRC request";
}
void p3turtle::setEnabled(bool b)
void p3turtle::setEnabled(bool b)
{
RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/
_turtle_routing_enabled = b;
@ -181,7 +188,7 @@ bool p3turtle::enabled() const
}
void p3turtle::setSessionEnabled(bool b)
void p3turtle::setSessionEnabled(bool b)
{
RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/
_turtle_routing_session_enabled = b;
@ -239,7 +246,7 @@ int p3turtle::tick()
RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/
_last_tunnel_management_time = now ;
// Update traffic statistics. The constants are important: they allow a smooth variation of the
// Update traffic statistics. The constants are important: they allow a smooth variation of the
// traffic speed, which is used to moderate tunnel requests statistics.
//
_traffic_info = _traffic_info*0.9 + _traffic_info_buffer* (0.1 / (float)TIME_BETWEEN_TUNNEL_MANAGEMENT_CALLS) ;
@ -367,8 +374,8 @@ void p3turtle::manageTunnels()
// - the hash hasn't been tunneled for more than REGULAR_TUNNEL_DIGGING_TIME seconds, even if downloading.
//
// Candidate hashes are sorted, by olderness. The older gets tunneled first. At most MAX_TUNNEL_REQS_PER_SECOND are
// treated at once, as this method is called every second.
// Note: Because REGULAR_TUNNEL_DIGGING_TIME is larger than EMPTY_TUNNELS_DIGGING_TIME, files being downloaded get
// treated at once, as this method is called every second.
// Note: Because REGULAR_TUNNEL_DIGGING_TIME is larger than EMPTY_TUNNELS_DIGGING_TIME, files being downloaded get
// re-tunneled in priority. As this happens less, they don't obliterate tunneling for files that have no tunnels yet.
std::vector<std::pair<TurtleFileHash,time_t> > hashes_to_digg ;
@ -549,7 +556,7 @@ void p3turtle::autoWash()
// Now remove all the virtual peers ids at the client services. Off mutex!
//
for(uint32_t i=0;i<services_vpids_to_remove.size();++i)
{
#ifdef P3TURTLE_DEBUG
@ -611,7 +618,7 @@ void p3turtle::locked_closeTunnel(TurtleTunnelId tid,std::vector<std::pair<RsTur
// Let's be cautious. Normally we should never be here without consistent information,
// but still, this happens, rarely.
//
if(_virtual_peers.find(vpid) != _virtual_peers.end())
if(_virtual_peers.find(vpid) != _virtual_peers.end())
_virtual_peers.erase(_virtual_peers.find(vpid)) ;
std::map<TurtleFileHash,TurtleHashInfo>::iterator it(_incoming_file_hashes.find(hash)) ;
@ -656,7 +663,7 @@ void p3turtle::locked_closeTunnel(TurtleTunnelId tid,std::vector<std::pair<RsTur
// Also remove the associated virtual peer
//
if(_virtual_peers.find(vpid) != _virtual_peers.end())
if(_virtual_peers.find(vpid) != _virtual_peers.end())
_virtual_peers.erase(_virtual_peers.find(vpid)) ;
}
}
@ -721,7 +728,7 @@ bool p3turtle::loadList(std::list<RsItem*>& load)
RsConfigKeyValueSet *vitem = dynamic_cast<RsConfigKeyValueSet*>(*it) ;
if(vitem != NULL)
for(std::list<RsTlvKeyValue>::const_iterator kit = vitem->tlvkvs.pairs.begin(); kit != vitem->tlvkvs.pairs.end(); ++kit)
for(std::list<RsTlvKeyValue>::const_iterator kit = vitem->tlvkvs.pairs.begin(); kit != vitem->tlvkvs.pairs.end(); ++kit)
{
if(kit->key == "TURTLE_CONFIG_MAX_TR_RATE")
{
@ -821,7 +828,7 @@ int p3turtle::handleIncoming()
RsTurtleGenericTunnelItem *gti = dynamic_cast<RsTurtleGenericTunnelItem *>(item) ;
if(gti != NULL)
routeGenericTunnelItem(gti) ; /// Generic packets, that travel through established tunnels.
routeGenericTunnelItem(gti) ; /// Generic packets, that travel through established tunnels.
else /// These packets should be destroyed by the client.
{
/// Special packets that require specific treatment, because tunnels do not exist for these packets.
@ -830,10 +837,12 @@ int p3turtle::handleIncoming()
switch(item->PacketSubType())
{
case RS_TURTLE_SUBTYPE_STRING_SEARCH_REQUEST:
case RS_TURTLE_SUBTYPE_GENERIC_SEARCH_REQUEST:
case RS_TURTLE_SUBTYPE_REGEXP_SEARCH_REQUEST: handleSearchRequest(dynamic_cast<RsTurtleSearchRequestItem *>(item)) ;
break ;
case RS_TURTLE_SUBTYPE_SEARCH_RESULT : handleSearchResult(dynamic_cast<RsTurtleSearchResultItem *>(item)) ;
case RS_TURTLE_SUBTYPE_GENERIC_SEARCH_RESULT :
case RS_TURTLE_SUBTYPE_FT_SEARCH_RESULT : handleSearchResult(dynamic_cast<RsTurtleSearchResultItem *>(item)) ;
break ;
case RS_TURTLE_SUBTYPE_OPEN_TUNNEL : handleTunnelRequest(dynamic_cast<RsTurtleOpenTunnelItem *>(item)) ;
@ -859,8 +868,6 @@ int p3turtle::handleIncoming()
//
void p3turtle::handleSearchRequest(RsTurtleSearchRequestItem *item)
{
RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/
// take a look at the item and test against inconsistent values
// - If the item destimation is
@ -868,7 +875,7 @@ void p3turtle::handleSearchRequest(RsTurtleSearchRequestItem *item)
std::cerr << "Received search request from peer " << item->PeerId() << ": " << std::endl ;
item->print(std::cerr,0) ;
#endif
uint32_t item_size = RsTurtleSerialiser().size(item);
if(item_size > TURTLE_MAX_SEARCH_REQ_ACCEPTED_SERIAL_SIZE)
@ -879,27 +886,57 @@ void p3turtle::handleSearchRequest(RsTurtleSearchRequestItem *item)
std::cerr << " Caught a turtle search item with arbitrary large size from " << item->PeerId() << " of size " << item_size << " and depth " << item->depth << ". This is not allowed => dropping." << std::endl;
return ;
}
if(_search_requests_origins.size() > MAX_ALLOWED_SR_IN_CACHE)
{
RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/
if(_search_requests_origins.size() > MAX_ALLOWED_SR_IN_CACHE)
{
#ifdef P3TURTLE_DEBUG
std::cerr << " Dropping, because the search request cache is full." << std::endl ;
std::cerr << " Dropping, because the search request cache is full." << std::endl ;
#endif
std::cerr << " More than " << MAX_ALLOWED_SR_IN_CACHE << " search request in cache. A peer is probably trying to flood your network See the depth charts to find him." << std::endl;
return ;
std::cerr << " More than " << MAX_ALLOWED_SR_IN_CACHE << " search request in cache. A peer is probably trying to flood your network See the depth charts to find him." << std::endl;
return ;
}
// If the item contains an already handled search request, give up. This
// happens when the same search request gets relayed by different peers
//
if(_search_requests_origins.find(item->request_id) != _search_requests_origins.end())
{
#ifdef P3TURTLE_DEBUG
std::cerr << " This is a bouncing request. Ignoring and deleting it." << std::endl ;
#endif
return ;
}
}
// If the item contains an already handled search request, give up. This
// happens when the same search request gets relayed by different peers
//
if(_search_requests_origins.find(item->request_id) != _search_requests_origins.end())
// Perform local search off-mutex,because this might call some services that are above turtle in the mutex chain.
uint32_t search_result_count = 0;
uint32_t max_allowed_hits = TURTLE_SEARCH_RESULT_MAX_HITS_DEFAULT;
if(item->PeerId() != _own_id) // is the request not coming from us?
{
#ifdef P3TURTLE_DEBUG
std::cerr << " This is a bouncing request. Ignoring and deleting it." << std::endl ;
std::cerr << " Request not from us. Performing local search" << std::endl ;
#endif
return ;
std::list<RsTurtleSearchResultItem*> search_results ;
performLocalSearch(item,search_result_count,search_results,max_allowed_hits) ;
for(auto it(search_results.begin());it!=search_results.end();++it)
{
(*it)->request_id = item->request_id ;
(*it)->depth = 0 ;
(*it)->PeerId(item->PeerId()) ;
sendItem(*it) ;
}
}
RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/
// This is a new request. Let's add it to the request map, and forward it to
// open peers.
@ -907,67 +944,17 @@ void p3turtle::handleSearchRequest(RsTurtleSearchRequestItem *item)
req.origin = item->PeerId() ;
req.time_stamp = time(NULL) ;
req.depth = item->depth ;
req.result_count = 0;
req.result_count = search_result_count;
req.keywords = item->GetKeywords() ;
// If it's not for us, perform a local search. If something found, forward the search result back.
if(item->PeerId() != _own_id)
{
#ifdef P3TURTLE_DEBUG
std::cerr << " Request not from us. Performing local search" << std::endl ;
#endif
std::list<TurtleFileInfo> result ;
item->performLocalSearch(result) ;
RsTurtleSearchResultItem *res_item = NULL ;
uint32_t item_size = 0 ;
#ifdef P3TURTLE_DEBUG
if(!result.empty())
std::cerr << " " << result.size() << " matches found. Sending back to origin (" << item->PeerId() << ")." << std::endl ;
#endif
while(!result.empty() && req.result_count < TURTLE_SEARCH_RESULT_MAX_HITS)
{
// Let's chop search results items into several chunks of finite size to avoid exceeding streamer's capacity.
//
static const uint32_t RSTURTLE_MAX_SEARCH_RESPONSE_SIZE = 10000 ;
if(res_item == NULL)
{
res_item = new RsTurtleSearchResultItem ;
item_size = 0 ;
res_item->depth = 0 ;
res_item->request_id = item->request_id ;
res_item->PeerId(item->PeerId()) ; // send back to the same guy
}
res_item->result.push_back(result.front()) ;
++req.result_count ; // increase hit number for this particular search request.
item_size += 8 /* size */ + result.front().hash.serial_size() + result.front().name.size() ;
result.pop_front() ;
if(item_size > RSTURTLE_MAX_SEARCH_RESPONSE_SIZE || result.empty() || req.result_count >= TURTLE_SEARCH_RESULT_MAX_HITS)
{
#ifdef P3TURTLE_DEBUG
std::cerr << " Sending back chunk of size " << item_size << ", for " << res_item->result.size() << " elements." << std::endl ;
#endif
sendItem(res_item) ;
res_item = NULL ;
}
}
}
req.service_id = item->serviceId() ;
req.max_allowed_hits = max_allowed_hits;
// if enough has been sent back already, do not sarch further
#ifdef P3TURTLE_DEBUG
std::cerr << " result count = " << req.result_count << std::endl;
#endif
if(req.result_count >= TURTLE_SEARCH_RESULT_MAX_HITS)
if(req.result_count >= max_allowed_hits)
return ;
// If search depth not too large, also forward this search request to all other peers.
@ -1004,14 +991,14 @@ void p3turtle::handleSearchRequest(RsTurtleSearchRequestItem *item)
// Copy current item and modify it.
RsTurtleSearchRequestItem *fwd_item = item->clone() ;
// increase search depth, except in some rare cases, to prevent correlation between
// increase search depth, except in some rare cases, to prevent correlation between
// TR sniffing and friend names. The strategy is to not increase depth if the depth
// is 1:
// If B receives a TR of depth 1 from A, B cannot deduice that A is downloading the
// file, since A might have shifted the depth.
//
if(!random_dshift)
++(fwd_item->depth) ;
++(fwd_item->depth) ;
fwd_item->PeerId(*it) ;
@ -1025,67 +1012,194 @@ void p3turtle::handleSearchRequest(RsTurtleSearchRequestItem *item)
#endif
}
// This function should be removed in the future, when file search will also use generic search items.
void p3turtle::performLocalSearch(RsTurtleSearchRequestItem *item,uint32_t& req_result_count,std::list<RsTurtleSearchResultItem*>& search_results,uint32_t& max_allowed_hits)
{
RsTurtleFileSearchRequestItem *ftsearch = dynamic_cast<RsTurtleFileSearchRequestItem*>(item) ;
if(ftsearch != NULL)
{
performLocalSearch_files(ftsearch,req_result_count,search_results,max_allowed_hits) ;
return ;
}
RsTurtleGenericSearchRequestItem *gnsearch = dynamic_cast<RsTurtleGenericSearchRequestItem*>(item) ;
if(gnsearch != NULL)
{
performLocalSearch_generic(gnsearch,req_result_count,search_results,max_allowed_hits) ;
return ;
}
}
void p3turtle::performLocalSearch_generic(RsTurtleGenericSearchRequestItem *item, uint32_t& req_result_count, std::list<RsTurtleSearchResultItem*>& result,uint32_t& max_allowed_hits)
{
unsigned char *search_result_data = NULL ;
uint32_t search_result_data_len = 0 ;
RsTurtleClientService *client = NULL ;
{
RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/
auto it = _registered_services.find(item->service_id) ;
if(it == _registered_services.end())
return ;
client = it->second ;
}
if(client->receiveSearchRequest(item->search_data,item->search_data_len,search_result_data,search_result_data_len,max_allowed_hits))
{
RsTurtleGenericSearchResultItem *result_item = new RsTurtleGenericSearchResultItem ;
result_item->result_data = search_result_data ;
result_item->result_data_len = search_result_data_len ;
result.push_back(result_item) ;
}
}
void p3turtle::performLocalSearch_files(RsTurtleFileSearchRequestItem *item,uint32_t& req_result_count,std::list<RsTurtleSearchResultItem*>& result,uint32_t& max_allowed_hits)
{
#ifdef P3TURTLE_DEBUG
std::cerr << "Performing rsFiles->search()" << std::endl ;
#endif
// now, search!
std::list<TurtleFileInfo> initialResults ;
item->search(initialResults) ;
#ifdef P3TURTLE_DEBUG
std::cerr << initialResults.size() << " matches found." << std::endl ;
#endif
result.clear() ;
RsTurtleFTSearchResultItem *res_item = NULL ;
uint32_t item_size = 0 ;
static const uint32_t RSTURTLE_MAX_SEARCH_RESPONSE_SIZE = 10000 ;
max_allowed_hits = TURTLE_SEARCH_RESULT_MAX_HITS_FILES;
for(auto it(initialResults.begin());it!=initialResults.end();++it)
{
if(res_item == NULL)
{
res_item = new RsTurtleFTSearchResultItem ;
item_size = 0 ;
result.push_back(res_item) ;
}
res_item->result.push_back(*it);
// Let's chop search results items into several chunks of finite size to avoid exceeding streamer's capacity.
//
++req_result_count ; // increase hit number for this particular search request.
item_size += 8 /* size */ + it->hash.serial_size() + it->name.size() ;
if(item_size > RSTURTLE_MAX_SEARCH_RESPONSE_SIZE || req_result_count >= max_allowed_hits)
{
#ifdef P3TURTLE_DEBUG
std::cerr << " Sending back chunk of size " << item_size << ", for " << res_item->result.size() << " elements." << std::endl ;
#endif
res_item = NULL ; // forces creation of a new item.
}
}
}
void p3turtle::handleSearchResult(RsTurtleSearchResultItem *item)
{
RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/
// Find who actually sent the corresponding request.
//
std::map<TurtleRequestId,TurtleSearchRequestInfo>::iterator it = _search_requests_origins.find(item->request_id) ;
#ifdef P3TURTLE_DEBUG
std::cerr << "Received search result:" << std::endl ;
item->print(std::cerr,0) ;
#endif
if(it == _search_requests_origins.end())
std::list<std::pair<RsTurtleSearchResultItem*,RsTurtleClientService*> > results_to_notify_off_mutex ;
{
// This is an error: how could we receive a search result corresponding to a search item we
// have forwarded but that it not in the list ??
RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/
// Find who actually sent the corresponding request.
//
std::map<TurtleRequestId,TurtleSearchRequestInfo>::iterator it = _search_requests_origins.find(item->request_id) ;
std::cerr << __PRETTY_FUNCTION__ << ": search result has no peer direction!" << std::endl ;
return ;
}
// Is this result's target actually ours ?
if(it->second.origin == _own_id)
{
it->second.result_count += item->result.size() ;
returnSearchResult(item) ; // Yes, so send upward.
}
else
{ // Nope, so forward it back.
#ifdef P3TURTLE_DEBUG
std::cerr << " Forwarding result back to " << it->second.origin << std::endl;
std::cerr << "Received search result:" << std::endl ;
item->print(std::cerr,0) ;
#endif
// We update the total count forwarded back, and chop it to TURTLE_SEARCH_RESULT_MAX_HITS.
uint32_t n = item->result.size(); // not so good!
if(it->second.result_count >= TURTLE_SEARCH_RESULT_MAX_HITS)
if(it == _search_requests_origins.end())
{
std::cerr << "(WW) exceeded turtle search result to forward. Req=" << std::hex << item->request_id << std::dec << ": dropping item with " << n << " elements." << std::endl;
// This is an error: how could we receive a search result corresponding to a search item we
// have forwarded but that it not in the list ??
std::cerr << __PRETTY_FUNCTION__ << ": search result for request " << std::hex << item->request_id << std::dec << " has no peer direction!" << std::endl ;
return ;
}
if(it->second.result_count + n > TURTLE_SEARCH_RESULT_MAX_HITS)
{
for(uint32_t i=it->second.result_count + n; i>TURTLE_SEARCH_RESULT_MAX_HITS;--i)
item->result.pop_back() ;
// Is this result's target actually ours ?
it->second.result_count = TURTLE_SEARCH_RESULT_MAX_HITS ;
if(it->second.origin == _own_id)
{
it->second.result_count += item->count() ;
auto it2 = _registered_services.find(it->second.service_id) ;
if(it2 != _registered_services.end())
results_to_notify_off_mutex.push_back(std::make_pair(item,it2->second)) ;
else
std::cerr << "(EE) cannot find client service for ID " << std::hex << it->second.service_id << std::dec << ": search result item will be dropped." << std::endl;
}
else
it->second.result_count += n ;
{ // Nope, so forward it back.
#ifdef P3TURTLE_DEBUG
std::cerr << " Forwarding result back to " << it->second.origin << std::endl;
#endif
// We update the total count forwarded back, and chop it to TURTLE_SEARCH_RESULT_MAX_HITS.
RsTurtleSearchResultItem *fwd_item = new RsTurtleSearchResultItem(*item) ; // copy the item
uint32_t n = item->count(); // not so good!
// Normally here, we should setup the forward adress, so that the owner's
// of the files found can be further reached by a tunnel.
if(it->second.result_count >= it->second.max_allowed_hits)
{
std::cerr << "(WW) exceeded turtle search result to forward. Req=" << std::hex << item->request_id << std::dec << ": dropping item with " << n << " elements." << std::endl;
return ;
}
fwd_item->PeerId(it->second.origin) ;
fwd_item->depth = 0 ; // obfuscate the depth for non immediate friends. Result will always be 0. This effectively removes the information.
if(it->second.result_count + n > it->second.max_allowed_hits)
{
for(uint32_t i=it->second.result_count + n; i>it->second.max_allowed_hits;--i)
item->pop() ;
sendItem(fwd_item) ;
it->second.result_count = it->second.max_allowed_hits ;
}
else
it->second.result_count += n ;
RsTurtleSearchResultItem *fwd_item = item->duplicate();
// 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->depth = 0 ; // obfuscate the depth for non immediate friends. Result will always be 0. This effectively removes the information.
sendItem(fwd_item) ;
}
}
// now we notify clients off-mutex.
for(auto it(results_to_notify_off_mutex.begin());it!=results_to_notify_off_mutex.end();++it)
{
// Hack to use the old search result handling in ftServer. Normally ftServer should use the new method with serialized result.
#warning make sure memory is correctly deleted here
RsTurtleFTSearchResultItem *ftsr = dynamic_cast<RsTurtleFTSearchResultItem*>(it->first) ;
if(ftsr!=NULL)
{
RsServer::notify()->notifyTurtleSearchResult(ftsr->request_id,ftsr->result) ;
continue ;
}
RsTurtleGenericSearchResultItem *gnsr = dynamic_cast<RsTurtleGenericSearchResultItem*>(it->first) ;
if(gnsr!=NULL)
(*it).second->receiveSearchResult(gnsr->request_id,gnsr->result_data,gnsr->result_data_len) ;
}
}
// -----------------------------------------------------------------------------------//
@ -1147,8 +1261,8 @@ void p3turtle::routeGenericTunnelItem(RsTurtleGenericTunnelItem *item)
// Let's figure out whether this packet is for us or not.
if(item->PeerId() == tunnel.local_dst && tunnel.local_src != _own_id) //direction == RsTurtleGenericTunnelItem::DIRECTION_CLIENT &&
{
if(item->PeerId() == tunnel.local_dst && tunnel.local_src != _own_id) //direction == RsTurtleGenericTunnelItem::DIRECTION_CLIENT &&
{
#ifdef P3TURTLE_DEBUG
std::cerr << " Forwarding generic item to peer " << tunnel.local_src << std::endl ;
#endif
@ -1186,7 +1300,7 @@ void p3turtle::routeGenericTunnelItem(RsTurtleGenericTunnelItem *item)
// The packet was not forwarded, so it is for us. Let's treat it.
// This is done off-mutex, to avoid various deadlocks
//
handleRecvGenericTunnelItem(item) ;
delete item ;
@ -1309,13 +1423,13 @@ void p3turtle::sendTurtleData(const RsPeerId& virtual_peer_id,RsTurtleGenericTun
if(tunnel.local_src == _own_id)
{
item->setTravelingDirection(RsTurtleGenericTunnelItem::DIRECTION_SERVER) ;
item->setTravelingDirection(RsTurtleGenericTunnelItem::DIRECTION_SERVER) ;
item->PeerId(tunnel.local_dst) ;
_traffic_info_buffer.data_dn_Bps += ss ;
}
else if(tunnel.local_dst == _own_id)
{
item->setTravelingDirection(RsTurtleGenericTunnelItem::DIRECTION_CLIENT) ;
item->setTravelingDirection(RsTurtleGenericTunnelItem::DIRECTION_CLIENT) ;
item->PeerId(tunnel.local_src) ;
_traffic_info_buffer.data_up_Bps += ss ;
}
@ -1453,7 +1567,7 @@ void p3turtle::handleTunnelRequest(RsTurtleOpenTunnelItem *item)
RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/
std::map<TurtleTunnelRequestId,TurtleTunnelRequestInfo>::iterator it = _tunnel_requests_origins.find(item->request_id) ;
if(it != _tunnel_requests_origins.end())
{
#ifdef P3TURTLE_DEBUG
@ -1556,7 +1670,7 @@ void p3turtle::handleTunnelRequest(RsTurtleOpenTunnelItem *item)
// - the tunnel id will now be unique for a given route
// - allows a better balance of bandwidth for a given transfer
// - avoid the waste of items that get lost when re-routing a tunnel
#ifdef P3TURTLE_DEBUG
std::cerr << "Perturbating partial tunnel id. Original=" << std::hex << item->partial_tunnel_id ;
#endif
@ -1587,7 +1701,7 @@ void p3turtle::handleTunnelRequest(RsTurtleOpenTunnelItem *item)
forward_probability = 1.0f / nb_online_ids ;
// Setting forward_probability to 1/nb_online_ids forces at most one TR up per TR dn. But if we are overflooded by
// TR dn, we still need to control them to avoid flooding the pqiHandler outqueue. So we additionally moderate the
// TR dn, we still need to control them to avoid flooding the pqiHandler outqueue. So we additionally moderate the
// forward probability so as to reduct the output rate accordingly.
//
if(_traffic_info.tr_dn_Bps / (float)TUNNEL_REQUEST_PACKET_SIZE > _max_tr_up_rate)
@ -1613,7 +1727,7 @@ void p3turtle::handleTunnelRequest(RsTurtleOpenTunnelItem *item)
// Copy current item and modify it.
RsTurtleOpenTunnelItem *fwd_item = new RsTurtleOpenTunnelItem(*item) ;
// increase search depth, except in some rare cases, to prevent correlation between
// increase search depth, except in some rare cases, to prevent correlation between
// TR sniffing and friend names. The strategy is to not increase depth if the depth
// is 1:
// If B receives a TR of depth 1 from A, B cannot deduice that A is downloading the
@ -1770,7 +1884,9 @@ void p3turtle::handleTunnelResult(RsTurtleTunnelOkItem *item)
// ------------------------------ IO with libretroshare ----------------------------//
// -----------------------------------------------------------------------------------//
//
void RsTurtleStringSearchRequestItem::performLocalSearch(std::list<TurtleFileInfo>& result) const
void RsTurtleStringSearchRequestItem::search(std::list<TurtleFileInfo>& result) const
{
/* call to core */
std::list<DirDetails> initialResults;
@ -1793,7 +1909,7 @@ void RsTurtleStringSearchRequestItem::performLocalSearch(std::list<TurtleFileInf
for(std::list<DirDetails>::const_iterator it(initialResults.begin());it!=initialResults.end();++it)
{
// retain only file type
if (it->type == DIR_TYPE_DIR)
if (it->type == DIR_TYPE_DIR)
{
#ifdef P3TURTLE_DEBUG
std::cerr << " Skipping directory " << it->name << std::endl ;
@ -1809,7 +1925,7 @@ void RsTurtleStringSearchRequestItem::performLocalSearch(std::list<TurtleFileInf
result.push_back(i) ;
}
}
void RsTurtleRegExpSearchRequestItem::performLocalSearch(std::list<TurtleFileInfo>& result) const
void RsTurtleRegExpSearchRequestItem::search(std::list<TurtleFileInfo>& result) const
{
/* call to core */
std::list<DirDetails> initialResults;
@ -1832,7 +1948,7 @@ void RsTurtleRegExpSearchRequestItem::performLocalSearch(std::list<TurtleFileInf
for(std::list<DirDetails>::const_iterator it(initialResults.begin());it!=initialResults.end();++it)
{
// retain only file type
if (it->type == DIR_TYPE_DIR)
if (it->type == DIR_TYPE_DIR)
{
#ifdef P3TURTLE_DEBUG
std::cerr << " Skipping directory " << it->name << std::endl ;
@ -1904,6 +2020,34 @@ TurtleRequestId p3turtle::turtleSearch(const RsRegularExpression::LinearizedExpr
return id ;
}
TurtleRequestId p3turtle::turtleSearch(unsigned char *search_bin_data,uint32_t search_bin_data_len,RsTurtleClientService *client_service)
{
// generate a new search id.
TurtleRequestId id = generateRandomRequestId() ;
// Form a request packet that simulates a request from us.
//
RsTurtleGenericSearchRequestItem item ;
#ifdef P3TURTLE_DEBUG
std::cerr << "performing search. OwnId = " << _own_id << std::endl ;
#endif
item.PeerId(_own_id) ;
item.service_id = client_service->serviceId();
item.search_data = search_bin_data ;
item.search_data_len = search_bin_data_len ;
item.request_id = id ;
item.depth = 0 ;
// send it
handleSearchRequest(&item) ;
return id ;
}
void p3turtle::monitorTunnels(const RsFileHash& hash,RsTurtleClientService *client_service,bool allow_multi_tunnels)
{
{
@ -1944,29 +2088,49 @@ void p3turtle::monitorTunnels(const RsFileHash& hash,RsTurtleClientService *clie
IndicateConfigChanged() ; // initiates saving of handled hashes.
}
void p3turtle::returnSearchResult(RsTurtleSearchResultItem *item)
{
// just cout for now, but it should be notified to the gui
#ifdef P3TURTLE_DEBUG
std::cerr << " Returning result for search request " << HEX_PRINT(item->request_id) << " upwards." << std::endl ;
#endif
RsServer::notify()->notifyTurtleSearchResult(item->request_id,item->result) ;
}
// RsTurtleGxsSearchResultGroupSummaryItem *gxs_sr_gs = dynamic_cast<RsTurtleGxsSearchResultGroupSummaryItem*>(item) ;
//
// if(gxs_sr_gs != NULL)
// {
// RsServer::notify()->notifyTurtleSearchResult(gxs_sr_gs->request_id,gxs_sr_gs->result) ;
// return ;
// }
// RsTurtleGxsSearchResultGroupDataItem *gxs_sr_gd = dynamic_cast<RsTurtleGxsSearchResultGroupDataItem*>(item) ;
//
// if(gxs_sr_gd != NULL)
// {
//#warning MISSING CODE HERE TO HANDLE ENCRYPTED INCOMING GROUP DATA.
// //RsServer::notify()->notifyTurtleSearchResult(gxs_sr_gd->request_id,gxs_sr_gd->encrypted_nxs_group) ;
// return ;
// }
/// Warning: this function should never be called while the turtle mutex is locked.
/// Otherwize this is a possible source of cross-lock with the File mutex.
//
bool p3turtle::performLocalHashSearch(const TurtleFileHash& hash,const RsPeerId& peer_id,RsTurtleClientService *& service)
{
if(_registered_services.empty())
std::cerr << "Turtle router has no services registered. Tunnel requests cannot be handled." << std::endl;
std::map<uint16_t,RsTurtleClientService*> client_map ;
{
RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/
for(std::list<RsTurtleClientService*>::const_iterator it(_registered_services.begin());it!=_registered_services.end();++it)
if( (*it)->handleTunnelRequest(hash,peer_id))
if(_registered_services.empty())
{
std::cerr << "Turtle router has no services registered. Tunnel requests cannot be handled." << std::endl;
return false ;
}
client_map = _registered_services ;
}
for(auto it(client_map.begin());it!=client_map.end();++it)
if( (*it).second->handleTunnelRequest(hash,peer_id))
{
service = *it ;
service = it->second ;
return true ;
}
@ -1976,14 +2140,9 @@ bool p3turtle::performLocalHashSearch(const TurtleFileHash& hash,const RsPeerId&
void p3turtle::registerTunnelService(RsTurtleClientService *service)
{
#ifdef P3TURTLE_DEBUG
for(std::list<RsTurtleClientService*>::const_iterator it(_registered_services.begin());it!=_registered_services.end();++it)
if(service == *it)
throw std::runtime_error("p3turtle::registerTunnelService(): Cannot register the same service twice. Please fix the code!") ;
#endif
std::cerr << "p3turtle: registered new tunnel service " << (void*)service << std::endl;
std::cerr << "p3turtle: registered new tunnel service with ID=" << std::hex << service->serviceId() << std::dec << " and pointer " << (void*)service << std::endl;
_registered_services.push_back(service) ;
_registered_services[service->serviceId()] = service ;
_serialiser->registerClientService(service) ;
}
@ -2065,7 +2224,7 @@ std::string p3turtle::getPeerNameForVirtualPeerId(const RsPeerId& virtual_peer_i
std::map<TurtleVirtualPeerId,TurtleTunnelId>::const_iterator it(_virtual_peers.find(virtual_peer_id)) ;
if(it != _virtual_peers.end())
{
std::map<TurtleTunnelId,TurtleTunnel>::iterator it2( _local_tunnels.find(it->second) ) ;
std::map<TurtleTunnelId,TurtleTunnel>::iterator it2( _local_tunnels.find(it->second) ) ;
if(it2 != _local_tunnels.end())
{
if(it2->second.local_src == _own_id)
@ -2077,6 +2236,28 @@ std::string p3turtle::getPeerNameForVirtualPeerId(const RsPeerId& virtual_peer_i
return name;
}
bool p3turtle::encryptData(const unsigned char *clear_data,uint32_t clear_data_size,uint8_t *encryption_master_key,RsTurtleGenericDataItem *& encrypted_item)
{
unsigned char *encrypted_data = NULL ;
uint32_t encrypted_data_len = 0 ;
if(!librs::crypto::encryptAuthenticateData(clear_data,clear_data_size,encryption_master_key,encrypted_data,encrypted_data_len))
{
delete encrypted_item ;
return false ;
}
encrypted_item = new RsTurtleGenericDataItem ;
encrypted_item->data_bytes = encrypted_data ;
encrypted_item->data_size = encrypted_data_len ;
return true;
}
bool p3turtle::decryptItem(const RsTurtleGenericDataItem* encrypted_item, uint8_t *encryption_master_key, unsigned char *& decrypted_data, uint32_t& decrypted_data_size)
{
return librs::crypto::decryptAuthenticateData((unsigned char*)encrypted_item->data_bytes,encrypted_item->data_size,encryption_master_key,decrypted_data,decrypted_data_size);
}
void p3turtle::getInfo( std::vector<std::vector<std::string> >& hashes_info,
std::vector<std::vector<std::string> >& tunnels_info,
std::vector<TurtleSearchRequestDisplayInfo >& search_reqs_info,
@ -2111,12 +2292,12 @@ void p3turtle::getInfo( std::vector<std::vector<std::string> >& hashes_info,
tunnel.push_back(printNumber(it->first,true)) ;
std::string name;
if(mLinkMgr->getPeerName(it->second.local_src,name))
if(mLinkMgr->getPeerName(it->second.local_src,name))
tunnel.push_back(name) ;
else
tunnel.push_back(it->second.local_src.toStdString()) ;
if(mLinkMgr->getPeerName(it->second.local_dst,name))
if(mLinkMgr->getPeerName(it->second.local_dst,name))
tunnel.push_back(name) ;
else
tunnel.push_back(it->second.local_dst.toStdString());

View file

@ -166,10 +166,12 @@ class TurtleSearchRequestInfo
{
public:
TurtlePeerId origin ; // where the request came from.
uint32_t time_stamp ; // last time the tunnel was actually used. Used for cleaning old tunnels.
int depth ; // depth of the request. Used to optimize tunnel length.
uint32_t result_count; // responses to this request. Useful to avoid spamming tunnel responses.
std::string keywords;
uint32_t time_stamp ; // last time the tunnel was actually used. Used for cleaning old tunnels.
int depth ; // depth of the request. Used to optimize tunnel length.
uint32_t result_count; // responses to this request. Useful to avoid spamming tunnel responses.
std::string keywords;
uint16_t service_id; // ID of the client service who issues the request. This is null if the request does not have a local origin.
uint32_t max_allowed_hits;// Max number of hits allowed for this search. This actually depends on the type of search (files, GXS groups, GXS group data, etc)
};
class TurtleTunnelRequestInfo
{
@ -241,11 +243,16 @@ class p3turtle: public p3Service, public RsTurtle, public p3Config
// the request id, which will be further used by the gui to store results
// as they come back.
//
// Eventually, search requests should be handled by client services. We will therefore
// remove the specific file search packets from the turtle router.
//
virtual TurtleSearchRequestId turtleSearch(const std::string& string_to_match) ;
virtual TurtleSearchRequestId turtleSearch(const RsRegularExpression::LinearizedExpression& expr) ;
// The first two methods are old style search requests for FT, while the 3rd one is using a generic search data type, that is only to
// be deserialized by the service. The memory ownership is kept by the calling function. Similarly, the search response will be a
// generic data type that is to be deserialized by the client service.
//
// Eventually, search requests will use the generic system
// even for FT. We need to keep the old method for a while for backward compatibility.
//
virtual TurtleRequestId turtleSearch(const RsRegularExpression::LinearizedExpression& expr) ;
virtual TurtleRequestId turtleSearch(const std::string& string_to_match) ;
virtual TurtleRequestId turtleSearch(unsigned char *search_bin_data,uint32_t search_bin_data_len,RsTurtleClientService *client_service) ;
// Initiates tunnel handling for the given file hash. tunnels. Launches
// an exception if an error occurs during the initialization process. The
@ -329,6 +336,12 @@ class p3turtle: public p3Service, public RsTurtle, public p3Config
/// Send a data request into the correct tunnel for the given file hash
void sendTurtleData(const RsPeerId& virtual_peer_id, RsTurtleGenericTunnelItem *item) ;
/// Encrypts/decrypts an item, using a autenticated construction + chacha20, based on the given 32 bytes master key.
/// Input values are not touched (memory is not released). Memory ownership of outputs is left to the client.
///
static bool encryptData(const unsigned char *clear_data,uint32_t clear_data_size,uint8_t *encryption_master_key,RsTurtleGenericDataItem *& encrypted_item);
static bool decryptItem(const RsTurtleGenericDataItem *item, uint8_t* encryption_master_key, unsigned char *& decrypted_data,uint32_t& decrypted_data_size);
private:
//--------------------------- Admin/Helper functions -------------------------//
@ -382,10 +395,9 @@ class p3turtle: public p3Service, public RsTurtle, public p3Config
//------ Functions connecting the turtle router to other components.----------//
/// Performs a search calling local cache and search structure.
void performLocalSearch(const std::string& match_string,std::list<TurtleFileInfo>& result) ;
/// Returns a search result upwards (possibly to the gui)
void returnSearchResult(RsTurtleSearchResultItem *item) ;
void performLocalSearch (RsTurtleSearchRequestItem *item, uint32_t& req_result_count,std::list<RsTurtleSearchResultItem*>& result,uint32_t& max_allowed_hits) ;
void performLocalSearch_files (RsTurtleFileSearchRequestItem *item, uint32_t& req_result_count, std::list<RsTurtleSearchResultItem*>& result, uint32_t &max_allowed_hits) ;
void performLocalSearch_generic(RsTurtleGenericSearchRequestItem *item, uint32_t& req_result_count, std::list<RsTurtleSearchResultItem*>& result, uint32_t &max_allowed_hits) ;
/// Returns true if the file with given hash is hosted locally, and accessible in anonymous mode the supplied peer.
virtual bool performLocalHashSearch(const TurtleFileHash& hash,const RsPeerId& client_peer_id,RsTurtleClientService *& service);
@ -407,7 +419,7 @@ class p3turtle: public p3Service, public RsTurtle, public p3Config
std::map<TurtleTunnelRequestId,TurtleTunnelRequestInfo> _tunnel_requests_origins ;
/// stores adequate tunnels for each file hash locally managed
std::map<TurtleFileHash,TurtleHashInfo> _incoming_file_hashes ;
std::map<TurtleFileHash,TurtleHashInfo> _incoming_file_hashes ;
/// stores file info for each file we provide.
std::map<TurtleTunnelId,RsTurtleClientService *> _outgoing_tunnel_client_services ;
@ -422,7 +434,7 @@ class p3turtle: public p3Service, public RsTurtle, public p3Config
std::set<TurtleFileHash> _hashes_to_remove ;
/// List of client services that have regitered.
std::list<RsTurtleClientService*> _registered_services ;
std::map<uint16_t,RsTurtleClientService*> _registered_services ;
time_t _last_clean_time ;
time_t _last_tunnel_management_time ;

View file

@ -49,10 +49,12 @@ RsItem *RsTurtleSerialiser::create_item(uint16_t service,uint8_t item_subtype) c
{
case RS_TURTLE_SUBTYPE_STRING_SEARCH_REQUEST : return new RsTurtleStringSearchRequestItem();
case RS_TURTLE_SUBTYPE_REGEXP_SEARCH_REQUEST : return new RsTurtleRegExpSearchRequestItem();
case RS_TURTLE_SUBTYPE_SEARCH_RESULT : return new RsTurtleSearchResultItem();
case RS_TURTLE_SUBTYPE_FT_SEARCH_RESULT : return new RsTurtleFTSearchResultItem();
case RS_TURTLE_SUBTYPE_OPEN_TUNNEL : return new RsTurtleOpenTunnelItem();
case RS_TURTLE_SUBTYPE_TUNNEL_OK : return new RsTurtleTunnelOkItem();
case RS_TURTLE_SUBTYPE_GENERIC_DATA : return new RsTurtleGenericDataItem();
case RS_TURTLE_SUBTYPE_GENERIC_SEARCH_REQUEST : return new RsTurtleGenericSearchRequestItem();
case RS_TURTLE_SUBTYPE_GENERIC_SEARCH_RESULT : return new RsTurtleGenericSearchResultItem();
default:
break ;
@ -69,20 +71,44 @@ RsItem *RsTurtleSerialiser::create_item(uint16_t service,uint8_t item_subtype) c
return NULL ;
}
std::string RsTurtleGenericSearchRequestItem::GetKeywords()
{
return std::string("Generic search : " + RsUtil::BinToHex(search_data,search_data_len,10));
}
void RsTurtleStringSearchRequestItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx)
{
RsTypeSerializer::serial_process (j,ctx,TLV_TYPE_STR_VALUE,match_string,"match_string") ;
RsTypeSerializer::serial_process<uint32_t>(j,ctx,request_id,"request_id") ;
RsTypeSerializer::serial_process<uint16_t>(j,ctx,depth ,"depth") ;
}
void RsTurtleRegExpSearchRequestItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx)
{
RsTypeSerializer::serial_process<uint32_t>(j,ctx,request_id,"request_id") ;
RsTypeSerializer::serial_process<uint16_t>(j,ctx,depth,"depth") ;
RsTypeSerializer::serial_process(j,ctx,expr,"expr") ;
}
void RsTurtleGenericSearchRequestItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx)
{
RsTypeSerializer::serial_process<uint32_t>(j,ctx,request_id,"request_id") ;
RsTypeSerializer::serial_process<uint16_t>(j,ctx,depth,"depth") ;
RsTypeSerializer::serial_process<uint16_t>(j,ctx,service_id,"service_id") ;
RsTypeSerializer::serial_process<uint8_t >(j,ctx,request_type,"request_type") ;
RsTypeSerializer::TlvMemBlock_proxy prox(search_data,search_data_len) ;
RsTypeSerializer::serial_process(j,ctx,prox,"search_data") ;
}
RsTurtleSearchRequestItem *RsTurtleGenericSearchRequestItem::clone() const
{
RsTurtleGenericSearchRequestItem *sr = new RsTurtleGenericSearchRequestItem ;
memcpy(sr,this,sizeof(RsTurtleGenericSearchRequestItem)) ;
sr->search_data = (unsigned char*)rs_malloc(search_data_len) ;
memcpy(sr->search_data,search_data,search_data_len) ;
return sr ;
}
template<> uint32_t RsTypeSerializer::serial_size(const RsRegularExpression::LinearizedExpression& r)
{
uint32_t s = 0 ;
@ -164,12 +190,31 @@ template<> void RsTypeSerializer::print_data(const std::string& n, const RsRegul
RS_TYPE_SERIALIZER_TO_JSON_NOT_IMPLEMENTED_DEF(RsRegularExpression::LinearizedExpression)
RS_TYPE_SERIALIZER_FROM_JSON_NOT_IMPLEMENTED_DEF(RsRegularExpression::LinearizedExpression)
void RsTurtleSearchResultItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx)
void RsTurtleFTSearchResultItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx)
{
RsTypeSerializer::serial_process<uint32_t>(j,ctx,request_id,"request_id") ;
RsTypeSerializer::serial_process<uint16_t>(j,ctx,depth ,"depth") ;
RsTypeSerializer::serial_process (j,ctx,result ,"result") ;
}
void RsTurtleGenericSearchResultItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx)
{
RsTypeSerializer::serial_process<uint32_t>(j,ctx,request_id,"request_id") ;
RsTypeSerializer::serial_process<uint16_t>(j,ctx,depth ,"depth") ;
RsTypeSerializer::TlvMemBlock_proxy prox(result_data,result_data_len) ;
RsTypeSerializer::serial_process(j,ctx,prox,"search_data") ;
}
RsTurtleSearchResultItem *RsTurtleGenericSearchResultItem::duplicate() const
{
RsTurtleGenericSearchResultItem *sr = new RsTurtleGenericSearchResultItem ;
sr->result_data = (unsigned char*)rs_malloc(result_data_len) ;
memcpy(sr->result_data,result_data,result_data_len) ;
sr->result_data_len = result_data_len ;
sr->request_id = request_id ;
sr->depth = depth ;
return sr ;
}
template<> uint32_t RsTypeSerializer::serial_size(const TurtleFileInfo& i)
{

View file

@ -37,20 +37,24 @@
#include "serialiser/rsserializer.h"
const uint8_t RS_TURTLE_SUBTYPE_STRING_SEARCH_REQUEST = 0x01 ;
const uint8_t RS_TURTLE_SUBTYPE_SEARCH_RESULT = 0x02 ;
const uint8_t RS_TURTLE_SUBTYPE_FT_SEARCH_RESULT = 0x02 ;
const uint8_t RS_TURTLE_SUBTYPE_OPEN_TUNNEL = 0x03 ;
const uint8_t RS_TURTLE_SUBTYPE_TUNNEL_OK = 0x04 ;
const uint8_t RS_TURTLE_SUBTYPE_FILE_REQUEST = 0x07 ;
const uint8_t RS_TURTLE_SUBTYPE_FILE_DATA = 0x08 ;
const uint8_t RS_TURTLE_SUBTYPE_REGEXP_SEARCH_REQUEST = 0x09 ;
const uint8_t RS_TURTLE_SUBTYPE_GENERIC_DATA = 0x0a ;
const uint8_t RS_TURTLE_SUBTYPE_GENERIC_SEARCH_REQUEST = 0x0b ;
const uint8_t RS_TURTLE_SUBTYPE_GENERIC_SEARCH_RESULT = 0x0c ;
const uint8_t RS_TURTLE_SUBTYPE_FILE_MAP = 0x10 ;
const uint8_t RS_TURTLE_SUBTYPE_FILE_MAP_REQUEST = 0x11 ;
// const uint8_t RS_TURTLE_SUBTYPE_FILE_CRC = 0x12 ; // unused
// const uint8_t RS_TURTLE_SUBTYPE_FILE_CRC_REQUEST = 0x13 ;
const uint8_t RS_TURTLE_SUBTYPE_CHUNK_CRC = 0x14 ;
const uint8_t RS_TURTLE_SUBTYPE_CHUNK_CRC_REQUEST = 0x15 ;
// const uint8_t RS_TURTLE_SUBTYPE_FILE_CRC = 0x12 ; // unused
// const uint8_t RS_TURTLE_SUBTYPE_FILE_CRC_REQUEST = 0x13 ;
class TurtleSearchRequestInfo ;
/***********************************************************************************/
/* Basic Turtle Item Class */
@ -67,49 +71,66 @@ class RsTurtleItem: public RsItem
/* Specific packets */
/***********************************************************************************/
class RsTurtleSearchResultItem: public RsTurtleItem
{
public:
RsTurtleSearchResultItem() : RsTurtleItem(RS_TURTLE_SUBTYPE_SEARCH_RESULT), request_id(0), depth(0) { setPriorityLevel(QOS_PRIORITY_RS_TURTLE_SEARCH_RESULT) ;}
// Class hierarchy is
//
// RsTurtleItem
// |
// +---- RsTurtleSearchRequestItem
// | |
// | +---- RsTurtleFileSearchRequestItem
// | | |
// | | +---- RsTurtleStringSearchRequestItem
// | | |
// | | +---- RsTurtleReqExpSearchRequestItem
// | |
// | +---- RsTurtleGenericSearchRequestItem
// |
// +---- RsTurtleSearchResultItem
// |
// +---- RsTurtleFTSearchResultItem
// |
// +---- RsTurtleGenericSearchResultItem
//
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 ;
void clear() { result.clear() ; }
protected:
void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx);
};
class RsTurtleSearchResultItem ;
class RsTurtleSearchRequestItem: public RsTurtleItem
{
public:
RsTurtleSearchRequestItem(uint32_t subtype) : RsTurtleItem(subtype), request_id(0), depth(0) { setPriorityLevel(QOS_PRIORITY_RS_TURTLE_SEARCH_REQUEST) ;}
virtual ~RsTurtleSearchRequestItem() {}
virtual RsTurtleSearchRequestItem *clone() const = 0 ; // used for cloning in routing methods
virtual void performLocalSearch(std::list<TurtleFileInfo>&) const = 0 ; // abstracts the search method
virtual std::string GetKeywords() = 0;
virtual uint16_t serviceId() const= 0 ;
uint32_t request_id ; // randomly generated request id.
uint16_t depth ; // Used for limiting search depth.
};
class RsTurtleStringSearchRequestItem: public RsTurtleSearchRequestItem
class RsTurtleFileSearchRequestItem: public RsTurtleSearchRequestItem
{
public:
RsTurtleStringSearchRequestItem() : RsTurtleSearchRequestItem(RS_TURTLE_SUBTYPE_STRING_SEARCH_REQUEST) {}
RsTurtleFileSearchRequestItem(uint32_t subtype) : RsTurtleSearchRequestItem(subtype) {}
virtual ~RsTurtleFileSearchRequestItem() {}
virtual uint16_t serviceId() const { return RS_SERVICE_TYPE_FILE_TRANSFER ; }
virtual void search(std::list<TurtleFileInfo> &) const =0;
};
class RsTurtleStringSearchRequestItem: public RsTurtleFileSearchRequestItem
{
public:
RsTurtleStringSearchRequestItem() : RsTurtleFileSearchRequestItem(RS_TURTLE_SUBTYPE_STRING_SEARCH_REQUEST) {}
virtual ~RsTurtleStringSearchRequestItem() {}
virtual void search(std::list<TurtleFileInfo> &) const ;
std::string match_string ; // string to match
std::string GetKeywords() { return match_string; }
virtual RsTurtleSearchRequestItem *clone() const { return new RsTurtleStringSearchRequestItem(*this) ; }
virtual void performLocalSearch(std::list<TurtleFileInfo>&) const ;
void clear() { match_string.clear() ; }
@ -117,10 +138,11 @@ class RsTurtleStringSearchRequestItem: public RsTurtleSearchRequestItem
void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx);
};
class RsTurtleRegExpSearchRequestItem: public RsTurtleSearchRequestItem
class RsTurtleRegExpSearchRequestItem: public RsTurtleFileSearchRequestItem
{
public:
RsTurtleRegExpSearchRequestItem() : RsTurtleSearchRequestItem(RS_TURTLE_SUBTYPE_REGEXP_SEARCH_REQUEST) {}
RsTurtleRegExpSearchRequestItem() : RsTurtleFileSearchRequestItem(RS_TURTLE_SUBTYPE_REGEXP_SEARCH_REQUEST) {}
virtual ~RsTurtleRegExpSearchRequestItem() {}
RsRegularExpression::LinearizedExpression expr ; // Reg Exp in linearised mode
@ -131,15 +153,91 @@ class RsTurtleRegExpSearchRequestItem: public RsTurtleSearchRequestItem
delete ex;
return exs;
}
virtual RsTurtleSearchRequestItem *clone() const { return new RsTurtleRegExpSearchRequestItem(*this) ; }
virtual void performLocalSearch(std::list<TurtleFileInfo>&) const ;
virtual void search(std::list<TurtleFileInfo> &) const ;
virtual RsTurtleSearchRequestItem *clone() const { return new RsTurtleRegExpSearchRequestItem(*this) ; }
void clear() { expr = RsRegularExpression::LinearizedExpression(); }
protected:
void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx);
};
class RsTurtleGenericSearchRequestItem: public RsTurtleSearchRequestItem
{
public:
RsTurtleGenericSearchRequestItem() : RsTurtleSearchRequestItem(RS_TURTLE_SUBTYPE_GENERIC_SEARCH_REQUEST) {}
virtual ~RsTurtleGenericSearchRequestItem() { clear(); }
uint16_t service_id ; // service to search
uint32_t search_data_len ;
uint8_t request_type ; // type of request. This is used to limit the number of responses.
unsigned char *search_data ;
std::string GetKeywords() ;
virtual uint16_t serviceId() const { return service_id ; }
virtual RsTurtleSearchRequestItem *clone() const ;
virtual uint32_t requestType() const { return request_type; }
void clear() { free(search_data); search_data=NULL; search_data_len=0; }
protected:
void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx);
private:
RsTurtleGenericSearchRequestItem(const RsTurtleGenericSearchRequestItem&): RsTurtleSearchRequestItem(RS_TURTLE_SUBTYPE_GENERIC_SEARCH_REQUEST) {} // make the object non copi-able.
RsTurtleGenericSearchRequestItem& operator=(const RsTurtleGenericSearchRequestItem&) { return *this;}
};
class RsTurtleSearchResultItem: public RsTurtleItem
{
public:
RsTurtleSearchResultItem(uint8_t subtype) : RsTurtleItem(subtype), request_id(0), depth(0) { setPriorityLevel(QOS_PRIORITY_RS_TURTLE_SEARCH_RESULT) ;}
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.
virtual uint32_t count() const =0;
virtual void pop() =0;
virtual void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx)=0;
virtual RsTurtleSearchResultItem *duplicate() const =0;
};
class RsTurtleFTSearchResultItem: public RsTurtleSearchResultItem
{
public:
RsTurtleFTSearchResultItem() : RsTurtleSearchResultItem(RS_TURTLE_SUBTYPE_FT_SEARCH_RESULT){}
std::list<TurtleFileInfo> result ;
void clear() { result.clear() ; }
uint32_t count() const { return result.size() ; }
virtual void pop() { result.pop_back() ;}
virtual RsTurtleSearchResultItem *duplicate() const { return new RsTurtleFTSearchResultItem(*this) ; }
protected:
void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx);
};
class RsTurtleGenericSearchResultItem: public RsTurtleSearchResultItem
{
public:
RsTurtleGenericSearchResultItem() : RsTurtleSearchResultItem(RS_TURTLE_SUBTYPE_GENERIC_SEARCH_RESULT){}
virtual ~RsTurtleGenericSearchResultItem() {}
uint32_t count() const { return result_data_len/50 ; } // This is a blind size estimate. We should probably use the actual size to limit search results.
virtual void pop() {}
unsigned char *result_data ;
uint32_t result_data_len ;
virtual RsTurtleSearchResultItem *duplicate() const ;
void clear() { free(result_data); result_data=NULL; result_data_len=0; }
protected:
void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx);
};
/***********************************************************************************/
/* Turtle Tunnel Item classes */
/***********************************************************************************/
@ -149,10 +247,10 @@ class RsTurtleOpenTunnelItem: public RsTurtleItem
public:
RsTurtleOpenTunnelItem() : RsTurtleItem(RS_TURTLE_SUBTYPE_OPEN_TUNNEL), request_id(0), partial_tunnel_id(0), depth(0) { setPriorityLevel(QOS_PRIORITY_RS_TURTLE_OPEN_TUNNEL) ;}
TurtleFileHash file_hash ; // hash to match
uint32_t request_id ; // randomly generated request id.
TurtleFileHash file_hash ; // hash to match
uint32_t request_id ; // randomly generated request id.
uint32_t partial_tunnel_id ; // uncomplete tunnel id. Will be completed at destination.
uint16_t depth ; // Used for limiting search depth.
uint16_t depth ; // Used for limiting search depth.
void clear() { file_hash.clear() ;}
protected:
@ -188,24 +286,24 @@ class RsTurtleGenericTunnelItem: public RsTurtleItem
/// Does this packet stamps tunnels when it passes through ?
/// This is used for keeping trace weither tunnels are active or not.
virtual bool shouldStampTunnel() const = 0 ;
/// All tunnels derived from RsTurtleGenericTunnelItem should have a tunnel id to
/// All tunnels derived from RsTurtleGenericTunnelItem should have a tunnel id to
/// indicate which tunnel they are travelling through.
virtual TurtleTunnelId tunnelId() const { return tunnel_id ; }
/// Indicate weither the packet is a client packet (goign back to the
/// client) or a server packet (going to the server. Typically file
/// requests are server packets, whereas file data are client packets.
virtual Direction travelingDirection() const { return direction ; }
virtual void setTravelingDirection(Direction d) { direction = d; }
Direction direction ; // This does not need to be serialised. It's only used by the client services, optionnally,
// and is set by the turtle router according to which direction the item travels.
uint32_t tunnel_id ; // Id of the tunnel to travel through
};

View file

@ -39,51 +39,125 @@ class p3turtle ;
class RsTurtleClientService
{
public:
// Handling of tunnel request for the given hash. Most of the time, it's a search in a predefined list.
// The output info_string is used by the turtle router to display info about tunnels it manages. It is
// not passed to the tunnel.
/*!
* \brief serviceId
* Returns the ID of the client service. This is used to pass the ID to search requests, from the client services
* \return
* The service ID.
*/
virtual bool handleTunnelRequest(const RsFileHash& /*hash*/,const RsPeerId& /*peer_id*/) { return false ; }
virtual uint16_t serviceId() const
{
std::cerr << "!!!!!! Received request for service ID in turtle router client, but the client service is not handling it !!!!!!!" << std::endl ;
return 0 ;
}
/*!
* \brief handleTunnelRequest
Handling of tunnel request for the given hash. To be derived by the service in order to tell the turtle router
whether the service handles this hash or not. Most of the time, it's a search in a predefined list.
* \return true if the service
*/
virtual bool handleTunnelRequest(const RsFileHash& /*hash*/,const RsPeerId& /*peer_id*/) { return false ; }
// This method is called by the turtle router to send data that comes out of a turtle tunnel.
// The turtle router stays responsible for the memory management of data. Most of the time the
// data chunk is a serialized item to be de-serialized by the client service.
//
// Parameters:
// virtual_peer_id : name of the tunnel that sent the data
// data : memory chunk for the data
// size : size of data
// item->direction : direction of travel:
// RsTurtleGenericTunnelItem::DIRECTION_CLIENT: the service is acting as a client
// RsTurtleGenericTunnelItem::DIRECTION_CLIENT: the service is acting as a server
//
// Most of the time this parameter is not used by services, except when some info (such as chunk maps, chat items, etc) go
// both ways, and their nature cannot suffice to determine where they should be handled.
//
// By default (if not overloaded), the method will just free the data, as any subclass should do as well.
// Note: p3turtle stays owner of the item, so the client should not delete it!
//
virtual void receiveTurtleData(RsTurtleGenericTunnelItem */*item*/,const RsFileHash& /*hash*/,const RsPeerId& /*virtual_peer_id*/,RsTurtleGenericTunnelItem::Direction /*direction*/)
/*!
* \brief receiveTurtleData
* This method is called by the turtle router to send data that comes out of a turtle tunnel, and should
* be overloaded by the client service.
* The turtle router stays responsible for the memory management of data. Most of the time the
* data chunk is a serialized item to be de-serialized by the client service.
*
* Parameters:
* virtual_peer_id : name of the tunnel that sent the data
* data : memory chunk for the data
* size : size of data
* item->direction : direction of travel:
* RsTurtleGenericTunnelItem::DIRECTION_CLIENT: the service is acting as a client
* RsTurtleGenericTunnelItem::DIRECTION_CLIENT: the service is acting as a server
*
* Most of the time this parameter is not used by services, except when some info (such as chunk maps, chat items, etc) go
* both ways, and their nature cannot suffice to determine where they should be handled.
*
* By default (if not overloaded), the method will just free the data, as any subclass should do as well.
* Note: p3turtle stays owner of the item, so the client should not delete it!
*/
virtual void receiveTurtleData(const RsTurtleGenericTunnelItem * /* item */,const RsFileHash& /*hash*/,const RsPeerId& /*virtual_peer_id*/,RsTurtleGenericTunnelItem::Direction /*direction*/)
{
std::cerr << "!!!!!! Received Data from turtle router, but the client service is not handling it !!!!!!!!!!" << std::endl ;
}
// Method for creating specific items of the client service. The
// method has a default behavior of not doing anything, since most client
// services might only use the generic item already provided by the turtle
// router: RsTurtleGenericDataItem
/*!
* \brief receiveSearchRequest
* This method is called by the turtle router to notify the client of a search request in the form generic data. The returned
* result contains the serialised generic result returned by the client.
*
* The turtle router keeps the memory ownership over search_request_data
*
* \param search_request_data generic serialized search data
* \param search_request_data_len length of the serialized search data
* \param search_result_data generic serialized search result data
* \param search_result_data_len length of the serialized search result data
* \param max_allowed_hits max number of hits allowed to be sent back and forwarded
*
* \return true if the search is successful.
*/
virtual bool receiveSearchRequest(unsigned char */*search_request_data*/,
uint32_t /*search_request_data_len*/,
unsigned char *& /*search_result_data*/,
uint32_t& /*search_result_data_len*/,
uint32_t& /* max_allows_hits */)
{
std::cerr << "!!!!!! Received search result from turtle router, but the client service who requested it is not handling it !!!!!!!!!!" << std::endl ;
return false;
}
/*!
* \brief receiveSearchResult
* This method is called by the turtle router to notify the client of a search result. The result is serialized for the current class to read.
*
* \param search_result_data result data. Memory ownership is owned by the turtle router. So do not delete!
* \param search_result_data length of result data
*/
virtual void receiveSearchResult(TurtleSearchRequestId /* request_id */,unsigned char * /*search_result_data*/,uint32_t /*search_result_data_len*/)
{
std::cerr << "!!!!!! Received search result from turtle router, but the client service who requested it is not handling it !!!!!!!!!!" << std::endl ;
}
/*!
* \brief serializer
* Method for creating specific items of the client service. The
* method has a default behavior of not doing anything, since most client
* services might only use the generic item already provided by the turtle
* router: RsTurtleGenericDataItem
*
* \return the client's serializer is returned
*/
virtual RsServiceSerializer *serializer() { return NULL ; }
// These methods are called by the turtle router to add/remove virtual peers when tunnels are created/deleted
//
/*!
* \brief addVirtualPeer
* These methods are called by the turtle router to notify the client in order to add/remove virtual peers when tunnels are created/deleted
* These methods must be overloaded, because a service which does not care about tunel being openned or closed is not supposed to need tunnels.
*
* \param hash hash that the tunnel responds to
* \param virtual_peer_id virtual peer id provided by turtle to allow the client to send data into this tunnel. This peer is related to the tunnel itself
* rather than to its destination. As such, multiple peer ids may actually send data to the same computer because multiple tunnels
* arrive at the same location.
* \param dir dir indicates which side the cient will be talking to: CLIENT means that the client is the server. SERVER means that the client acts
* as a client (and therefore actually requested the tunnel).
*/
virtual void addVirtualPeer(const TurtleFileHash& hash,const TurtleVirtualPeerId& virtual_peer_id,RsTurtleGenericTunnelItem::Direction dir) = 0 ;
virtual void removeVirtualPeer(const TurtleFileHash& hash,const TurtleVirtualPeerId& virtual_peer_id) = 0 ;
// This function is mandatory. It should do two things:
// 1 - keep a pointer to the turtle router, so as to be able to send data (e.g. copy pt into a local variable)
// 2 - call pt->registerTunnelService(this), so that the TR knows that service and can send back information to it.
//
/*!
* \brief connectToTurtleRouter
* This function must be overloaded by the client. It should do two things:
* 1 - keep a pointer to the turtle router, so as to be able to send data (e.g. store pt into a local variable)
* 2 - call pt->registerTunnelService(this), so that the TR knows that service and can send back information to it.
*
* \param pt A pointer to the turtle router.
*/
virtual void connectToTurtleRouter(p3turtle *pt) = 0 ;
};