Merge pull request #1294 from csoler/v0.6-GXS-DistSync3-TurtleSearch

V0.6 gxs dist sync3 turtle search
This commit is contained in:
csoler 2018-07-19 22:59:43 +02:00 committed by GitHub
commit b8062f2e21
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
83 changed files with 4645 additions and 684 deletions

View File

@ -190,9 +190,9 @@ void FileSearchHandler::handleCreateSearch(Request &req, Response &resp)
// i have no idea what the reasons for two different search modes are
// rs-gui does it, so do we
if(words.size() == 1)
search_id = mTurtle->turtleSearch(words.front());
search_id = rsFiles->turtleSearch(words.front());
else
search_id = mTurtle->turtleSearch(lin_exp);
search_id = rsFiles->turtleSearch(lin_exp);
}
std::list<FileDetail> results;

View File

@ -0,0 +1,212 @@
/*******************************************************************************
* libretroshare/src/crypto: crypto.cc *
* *
* libretroshare: retroshare core library *
* *
* Copyright 2018 by Cyril Soler <csoler@users.sourceforge.net> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "rscrypto.h"
#include "util/rsrandom.h"
//#define CRYPTO_DEBUG 1
namespace librs {
namespace crypto {
#define RSCRYPTO_DEBUG() std::cerr << time(NULL) << " : RSCRYPTO : " << __FUNCTION__ << " : "
#define RSCRYPTO_ERROR() std::cerr << "(EE) RSCRYPTO ERROR : "
static const uint32_t ENCRYPTED_MEMORY_INITIALIZATION_VECTOR_SIZE = 12 ;
static const uint32_t ENCRYPTED_MEMORY_AUTHENTICATION_TAG_SIZE = 16 ;
static const uint32_t ENCRYPTED_MEMORY_HEADER_SIZE = 4 ;
static const uint32_t ENCRYPTED_MEMORY_EDATA_SIZE = 4 ;
static const uint8_t ENCRYPTED_MEMORY_FORMAT_AEAD_CHACHA20_POLY1305 = 0x01 ;
static const uint8_t ENCRYPTED_MEMORY_FORMAT_AEAD_CHACHA20_SHA256 = 0x02 ;
bool encryptAuthenticateData(const unsigned char *clear_data,uint32_t clear_data_size,uint8_t *encryption_master_key,unsigned char *& encrypted_data,uint32_t& encrypted_data_len)
{
uint8_t initialization_vector[ENCRYPTED_MEMORY_INITIALIZATION_VECTOR_SIZE] ;
RSRandom::random_bytes(initialization_vector,ENCRYPTED_MEMORY_INITIALIZATION_VECTOR_SIZE) ;
#ifdef CRYPTO_DEBUG
RSCRYPTO_DEBUG() << "ftServer::Encrypting ft item." << std::endl;
RSCRYPTO_DEBUG() << " random nonce : " << RsUtil::BinToHex(initialization_vector,ENCRYPTED_MEMORY_INITIALIZATION_VECTOR_SIZE) << std::endl;
#endif
uint32_t item_serialized_size = clear_data_size;//RsGenericSerializer().size(clear_item) ;
uint32_t total_data_size = ENCRYPTED_MEMORY_HEADER_SIZE + ENCRYPTED_MEMORY_INITIALIZATION_VECTOR_SIZE + ENCRYPTED_MEMORY_EDATA_SIZE + item_serialized_size + ENCRYPTED_MEMORY_AUTHENTICATION_TAG_SIZE ;
#ifdef CRYPTO_DEBUG
RSCRYPTO_DEBUG() << " clear part size : " << size(clear_item) << std::endl;
RSCRYPTO_DEBUG() << " total item size : " << total_data_size << std::endl;
#endif
encrypted_data = (unsigned char*)rs_malloc( total_data_size ) ;
encrypted_data_len = total_data_size ;
if(encrypted_data == NULL)
return false ;
uint8_t *edata = (uint8_t*)encrypted_data;
uint32_t edata_size = item_serialized_size;
uint32_t offset = 0;
edata[0] = 0xae ;
edata[1] = 0xad ;
edata[2] = ENCRYPTED_MEMORY_FORMAT_AEAD_CHACHA20_SHA256 ; // means AEAD_chacha20_sha256
edata[3] = 0x01 ;
offset += ENCRYPTED_MEMORY_HEADER_SIZE;
uint32_t aad_offset = offset ;
uint32_t aad_size = ENCRYPTED_MEMORY_INITIALIZATION_VECTOR_SIZE + ENCRYPTED_MEMORY_EDATA_SIZE ;
memcpy(&edata[offset], initialization_vector, ENCRYPTED_MEMORY_INITIALIZATION_VECTOR_SIZE) ;
offset += ENCRYPTED_MEMORY_INITIALIZATION_VECTOR_SIZE ;
edata[offset+0] = (edata_size >> 0) & 0xff ;
edata[offset+1] = (edata_size >> 8) & 0xff ;
edata[offset+2] = (edata_size >> 16) & 0xff ;
edata[offset+3] = (edata_size >> 24) & 0xff ;
offset += ENCRYPTED_MEMORY_EDATA_SIZE ;
memcpy(&edata[offset],clear_data,clear_data_size);
#ifdef CRYPTO_DEBUG
RSCRYPTO_DEBUG() << " clear item : " << RsUtil::BinToHex(&edata[offset],std::min(50,(int)total_data_size-(int)offset)) << "(...)" << std::endl;
#endif
uint32_t clear_item_offset = offset ;
offset += edata_size ;
uint32_t authentication_tag_offset = offset ;
assert(ENCRYPTED_MEMORY_AUTHENTICATION_TAG_SIZE + offset == total_data_size) ;
//uint8_t encryption_key[32] ;
//deriveEncryptionKey(hash,encryption_key) ;
if(edata[2] == ENCRYPTED_MEMORY_FORMAT_AEAD_CHACHA20_POLY1305)
librs::crypto::AEAD_chacha20_poly1305(encryption_master_key,initialization_vector,&edata[clear_item_offset],edata_size, &edata[aad_offset],aad_size, &edata[authentication_tag_offset],true) ;
else if(edata[2] == ENCRYPTED_MEMORY_FORMAT_AEAD_CHACHA20_SHA256)
librs::crypto::AEAD_chacha20_sha256 (encryption_master_key,initialization_vector,&edata[clear_item_offset],edata_size, &edata[aad_offset],aad_size, &edata[authentication_tag_offset],true) ;
else
return false ;
#ifdef CRYPTO_DEBUG
RSCRYPTO_DEBUG() << " encryption key : " << RsUtil::BinToHex(encryption_key,32) << std::endl;
RSCRYPTO_DEBUG() << " authen. tag : " << RsUtil::BinToHex(&edata[authentication_tag_offset],ENCRYPTED_MEMORY_AUTHENTICATION_TAG_SIZE) << std::endl;
RSCRYPTO_DEBUG() << " final item : " << RsUtil::BinToHex(&edata[0],std::min(50u,total_data_size)) << "(...)" << std::endl;
#endif
return true ;
}
// Decrypts the given item using aead-chacha20-poly1305
bool decryptAuthenticateData(const unsigned char *encrypted_data,uint32_t encrypted_data_len,uint8_t *encryption_master_key, unsigned char *& decrypted_data, uint32_t& decrypted_data_size)
{
//uint8_t encryption_key[32] ;
//deriveEncryptionKey(hash,encryption_key) ;
uint8_t *edata = (uint8_t*)encrypted_data;
uint32_t offset = 0;
if(encrypted_data_len < ENCRYPTED_MEMORY_HEADER_SIZE + ENCRYPTED_MEMORY_INITIALIZATION_VECTOR_SIZE + ENCRYPTED_MEMORY_EDATA_SIZE) return false ;
if(edata[0] != 0xae) return false ;
if(edata[1] != 0xad) return false ;
if(edata[2] != ENCRYPTED_MEMORY_FORMAT_AEAD_CHACHA20_POLY1305 && edata[2] != ENCRYPTED_MEMORY_FORMAT_AEAD_CHACHA20_SHA256) return false ;
if(edata[3] != 0x01) return false ;
offset += ENCRYPTED_MEMORY_HEADER_SIZE ;
uint32_t aad_offset = offset ;
uint32_t aad_size = ENCRYPTED_MEMORY_EDATA_SIZE + ENCRYPTED_MEMORY_INITIALIZATION_VECTOR_SIZE ;
uint8_t *initialization_vector = &edata[offset] ;
#ifdef CRYPTO_DEBUG
RSCRYPTO_DEBUG() << "ftServer::decrypting ft item." << std::endl;
RSCRYPTO_DEBUG() << " item data : " << RsUtil::BinToHex(edata,std::min(50u,encrypted_data_len) << "(...)" << std::endl;
RSCRYPTO_DEBUG() << " hash : " << hash << std::endl;
RSCRYPTO_DEBUG() << " encryption key : " << RsUtil::BinToHex(encryption_key,32) << std::endl;
RSCRYPTO_DEBUG() << " random nonce : " << RsUtil::BinToHex(initialization_vector,ENCRYPTED_MEMORY_INITIALIZATION_VECTOR_SIZE) << std::endl;
#endif
offset += ENCRYPTED_MEMORY_INITIALIZATION_VECTOR_SIZE ;
uint32_t edata_size = 0 ;
edata_size += ((uint32_t)edata[offset+0]) << 0 ;
edata_size += ((uint32_t)edata[offset+1]) << 8 ;
edata_size += ((uint32_t)edata[offset+2]) << 16 ;
edata_size += ((uint32_t)edata[offset+3]) << 24 ;
if(edata_size + ENCRYPTED_MEMORY_EDATA_SIZE + ENCRYPTED_MEMORY_AUTHENTICATION_TAG_SIZE + ENCRYPTED_MEMORY_INITIALIZATION_VECTOR_SIZE + ENCRYPTED_MEMORY_HEADER_SIZE != encrypted_data_len)
{
RSCRYPTO_ERROR() << " ERROR: encrypted data size is " << edata_size << ", should be " << encrypted_data_len - (ENCRYPTED_MEMORY_EDATA_SIZE + ENCRYPTED_MEMORY_AUTHENTICATION_TAG_SIZE + ENCRYPTED_MEMORY_INITIALIZATION_VECTOR_SIZE + ENCRYPTED_MEMORY_HEADER_SIZE ) << std::endl;
return false ;
}
offset += ENCRYPTED_MEMORY_EDATA_SIZE ;
uint32_t clear_item_offset = offset ;
uint32_t authentication_tag_offset = offset + edata_size ;
#ifdef CRYPTO_DEBUG
RSCRYPTO_DEBUG() << " authen. tag : " << RsUtil::BinToHex(&edata[authentication_tag_offset],ENCRYPTED_MEMORY_AUTHENTICATION_TAG_SIZE) << std::endl;
#endif
bool result ;
if(edata[2] == ENCRYPTED_MEMORY_FORMAT_AEAD_CHACHA20_POLY1305)
result = librs::crypto::AEAD_chacha20_poly1305(encryption_master_key,initialization_vector,&edata[clear_item_offset],edata_size, &edata[aad_offset],aad_size, &edata[authentication_tag_offset],false) ;
else if(edata[2] == ENCRYPTED_MEMORY_FORMAT_AEAD_CHACHA20_SHA256)
result = librs::crypto::AEAD_chacha20_sha256 (encryption_master_key,initialization_vector,&edata[clear_item_offset],edata_size, &edata[aad_offset],aad_size, &edata[authentication_tag_offset],false) ;
else
return false ;
#ifdef CRYPTO_DEBUG
RSCRYPTO_DEBUG() << " authen. result : " << result << std::endl;
RSCRYPTO_DEBUG() << " decrypted daya : " << RsUtil::BinToHex(&edata[clear_item_offset],std::min(50u,edata_size)) << "(...)" << std::endl;
#endif
if(!result)
{
RSCRYPTO_ERROR() << "(EE) decryption/authentication went wrong." << std::endl;
return false ;
}
decrypted_data_size = edata_size ;
decrypted_data = (unsigned char*)rs_malloc(edata_size) ;
if(decrypted_data == NULL)
{
std::cerr << "Failed to allocate memory for decrypted data chunk of size " << edata_size << std::endl;
return false ;
}
memcpy(decrypted_data,&edata[clear_item_offset],edata_size) ;
return true ;
}
}
}

View File

@ -0,0 +1,59 @@
/*******************************************************************************
* libretroshare/src/crypto: crypto.h *
* *
* libretroshare: retroshare core library *
* *
* Copyright 2018 by Cyril Soler <csoler@users.sourceforge.net> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#include "crypto/chacha20.h"
namespace librs
{
namespace crypto
{
/*!
* \brief encryptAuthenticateData
Encrypts/decrypts data, using a autenticated construction + chacha20, based on a given 32 bytes master key. The actual encryption using a randomized key
based on a 96 bits IV. Input values are not touched (memory is not released). Memory ownership of outputs is left to the client.
* \param clear_data input data to encrypt
* \param clear_data_size length of input data
* \param encryption_master_key encryption master key of length 32 bytes.
* \param encrypted_data encrypted data, allocated using malloc
* \param encrypted_data_len length of encrypted data
* \return
* true if everything went well.
*/
bool encryptAuthenticateData(const unsigned char *clear_data,uint32_t clear_data_size,uint8_t *encryption_master_key,unsigned char *& encrypted_data,uint32_t& encrypted_data_size);
/*!
* \brief decryptAuthenticateData
Encrypts/decrypts data, using a autenticated construction + chacha20, based on a given 32 bytes master key. The actual encryption using a randomized key
based on a 96 bits IV. Input values are not touched (memory is not released). Memory ownership of outputs is left to the client.
* \param encrypted_data input encrypted data
* \param encrypted_data_size input encrypted data length
* \param encryption_master_key encryption master key of length 32 bytes.
* \param decrypted_data decrypted data, allocated using malloc.
* \param decrypted_data_size length of allocated decrypted data.
* \return
* true if decryption + authentication are ok.
*/
bool decryptAuthenticateData(const unsigned char *encrypted_data,uint32_t encrypted_data_size, uint8_t* encryption_master_key, unsigned char *& decrypted_data,uint32_t& decrypted_data_size);
}
}

View File

@ -1234,6 +1234,21 @@ static const uint8_t ENCRYPTED_FT_FORMAT_AEAD_CHACHA20_SHA256 = 0x02 ;
bool ftServer::encryptItem(RsTurtleGenericTunnelItem *clear_item,const RsFileHash& hash,RsTurtleGenericDataItem *& encrypted_item)
{
#ifndef USE_NEW_METHOD
uint32_t item_serialized_size = size(clear_item) ;
RsTemporaryMemory data(item_serialized_size) ;
if(data == NULL)
return false ;
serialise(clear_item, data, &item_serialized_size);
uint8_t encryption_key[32] ;
deriveEncryptionKey(hash,encryption_key) ;
return p3turtle::encryptData(data,item_serialized_size,encryption_key,encrypted_item) ;
#else
uint8_t initialization_vector[ENCRYPTED_FT_INITIALIZATION_VECTOR_SIZE] ;
RSRandom::random_bytes(initialization_vector,ENCRYPTED_FT_INITIALIZATION_VECTOR_SIZE) ;
@ -1312,12 +1327,34 @@ bool ftServer::encryptItem(RsTurtleGenericTunnelItem *clear_item,const RsFileHas
#endif
return true ;
#endif
}
// Decrypts the given item using aead-chacha20-poly1305
bool ftServer::decryptItem(RsTurtleGenericDataItem *encrypted_item,const RsFileHash& hash,RsTurtleGenericTunnelItem *& decrypted_item)
bool ftServer::decryptItem(const RsTurtleGenericDataItem *encrypted_item,const RsFileHash& hash,RsTurtleGenericTunnelItem *& decrypted_item)
{
#ifndef USE_NEW_METHOD
unsigned char *data = NULL ;
uint32_t data_size = 0 ;
uint8_t encryption_key[32] ;
deriveEncryptionKey(hash,encryption_key) ;
if(!p3turtle::decryptItem(encrypted_item,encryption_key,data,data_size))
{
FTSERVER_ERROR() << "Cannot decrypt data!" << std::endl;
if(data)
free(data) ;
return false ;
}
decrypted_item = dynamic_cast<RsTurtleGenericTunnelItem*>(deserialise(data,&data_size)) ;
free(data);
return (decrypted_item != NULL);
#else
uint8_t encryption_key[32] ;
deriveEncryptionKey(hash,encryption_key) ;
@ -1393,6 +1430,7 @@ bool ftServer::decryptItem(RsTurtleGenericDataItem *encrypted_item,const RsFileH
return false ;
return true ;
#endif
}
bool ftServer::encryptHash(const RsFileHash& hash, RsFileHash& hash_of_hash)
@ -1430,9 +1468,34 @@ bool ftServer::findRealHash(const RsFileHash& hash, RsFileHash& real_hash)
return false ;
}
TurtleSearchRequestId ftServer::turtleSearch(const std::string& string_to_match)
{
return mTurtleRouter->turtleSearch(string_to_match) ;
}
TurtleSearchRequestId ftServer::turtleSearch(const RsRegularExpression::LinearizedExpression& expr)
{
return mTurtleRouter->turtleSearch(expr) ;
}
#warning we should do this here, but for now it is done by turtle router.
// // Dont delete the item. The client (p3turtle) is doing it after calling this.
// //
// void ftServer::receiveSearchResult(RsTurtleSearchResultItem *item)
// {
// RsTurtleFTSearchResultItem *ft_sr = dynamic_cast<RsTurtleFTSearchResultItem*>(item) ;
//
// if(ft_sr == NULL)
// {
// FTSERVER_ERROR() << "(EE) ftServer::receiveSearchResult(): item cannot be cast to a RsTurtleFTSearchResultItem" << std::endl;
// return ;
// }
//
// RsServer::notify()->notifyTurtleSearchResult(ft_sr->request_id,ft_sr->result) ;
// }
// Dont delete the item. The client (p3turtle) is doing it after calling this.
//
void ftServer::receiveTurtleData(RsTurtleGenericTunnelItem *i,
void ftServer::receiveTurtleData(const RsTurtleGenericTunnelItem *i,
const RsFileHash& hash,
const RsPeerId& virtual_peer_id,
RsTurtleGenericTunnelItem::Direction direction)
@ -1452,7 +1515,7 @@ void ftServer::receiveTurtleData(RsTurtleGenericTunnelItem *i,
}
RsTurtleGenericTunnelItem *decrypted_item ;
if(!decryptItem(dynamic_cast<RsTurtleGenericDataItem *>(i),real_hash,decrypted_item))
if(!decryptItem(dynamic_cast<const RsTurtleGenericDataItem *>(i),real_hash,decrypted_item))
{
FTSERVER_ERROR() << "(EE) decryption error." << std::endl;
return ;
@ -1468,7 +1531,7 @@ void ftServer::receiveTurtleData(RsTurtleGenericTunnelItem *i,
{
case RS_TURTLE_SUBTYPE_FILE_REQUEST:
{
RsTurtleFileRequestItem *item = dynamic_cast<RsTurtleFileRequestItem *>(i) ;
const RsTurtleFileRequestItem *item = dynamic_cast<const RsTurtleFileRequestItem *>(i) ;
if (item)
{
#ifdef SERVER_DEBUG
@ -1481,7 +1544,7 @@ void ftServer::receiveTurtleData(RsTurtleGenericTunnelItem *i,
case RS_TURTLE_SUBTYPE_FILE_DATA :
{
RsTurtleFileDataItem *item = dynamic_cast<RsTurtleFileDataItem *>(i) ;
const RsTurtleFileDataItem *item = dynamic_cast<const RsTurtleFileDataItem *>(i) ;
if (item)
{
#ifdef SERVER_DEBUG
@ -1489,7 +1552,7 @@ void ftServer::receiveTurtleData(RsTurtleGenericTunnelItem *i,
#endif
getMultiplexer()->recvData(virtual_peer_id,hash,0,item->chunk_offset,item->chunk_size,item->chunk_data) ;
item->chunk_data = NULL ; // this prevents deletion in the destructor of RsFileDataItem, because data will be deleted
const_cast<RsTurtleFileDataItem*>(item)->chunk_data = NULL ; // this prevents deletion in the destructor of RsFileDataItem, because data will be deleted
// down _ft_server->getMultiplexer()->recvData()...in ftTransferModule::recvFileData
}
}
@ -1497,7 +1560,7 @@ void ftServer::receiveTurtleData(RsTurtleGenericTunnelItem *i,
case RS_TURTLE_SUBTYPE_FILE_MAP :
{
RsTurtleFileMapItem *item = dynamic_cast<RsTurtleFileMapItem *>(i) ;
const RsTurtleFileMapItem *item = dynamic_cast<const RsTurtleFileMapItem *>(i) ;
if (item)
{
#ifdef SERVER_DEBUG
@ -1520,7 +1583,7 @@ void ftServer::receiveTurtleData(RsTurtleGenericTunnelItem *i,
case RS_TURTLE_SUBTYPE_CHUNK_CRC :
{
RsTurtleChunkCrcItem *item = dynamic_cast<RsTurtleChunkCrcItem *>(i) ;
const RsTurtleChunkCrcItem *item = dynamic_cast<const RsTurtleChunkCrcItem *>(i) ;
if (item)
{
#ifdef SERVER_DEBUG
@ -1533,7 +1596,7 @@ void ftServer::receiveTurtleData(RsTurtleGenericTunnelItem *i,
case RS_TURTLE_SUBTYPE_CHUNK_CRC_REQUEST:
{
RsTurtleChunkCrcRequestItem *item = dynamic_cast<RsTurtleChunkCrcRequestItem *>(i) ;
const RsTurtleChunkCrcRequestItem *item = dynamic_cast<const RsTurtleChunkCrcRequestItem *>(i) ;
if (item)
{
#ifdef SERVER_DEBUG

View File

@ -95,8 +95,11 @@ public:
// Implements RsTurtleClientService
//
uint16_t serviceId() const { return RS_SERVICE_TYPE_FILE_TRANSFER ; }
virtual bool handleTunnelRequest(const RsFileHash& hash,const RsPeerId& peer_id) ;
virtual void receiveTurtleData(RsTurtleGenericTunnelItem *item,const RsFileHash& hash,const RsPeerId& virtual_peer_id,RsTurtleGenericTunnelItem::Direction direction) ;
virtual void receiveTurtleData(const RsTurtleGenericTunnelItem *item,const RsFileHash& hash,const RsPeerId& virtual_peer_id,RsTurtleGenericTunnelItem::Direction direction) ;
//virtual void receiveSearchResult(RsTurtleSearchResultItem *item);// TODO
virtual RsItem *create_item(uint16_t service,uint8_t item_type) const ;
virtual RsServiceSerializer *serializer() { return this ; }
@ -143,6 +146,9 @@ public:
virtual void setFilePermDirectDL(uint32_t perm) ;
virtual uint32_t filePermDirectDL() ;
virtual TurtleSearchRequestId turtleSearch(const std::string& string_to_match) ;
virtual TurtleSearchRequestId turtleSearch(const RsRegularExpression::LinearizedExpression& expr) ;
/***
* Control of Downloads Priority.
***/
@ -250,7 +256,7 @@ public:
static void deriveEncryptionKey(const RsFileHash& hash, uint8_t *key);
bool encryptItem(RsTurtleGenericTunnelItem *clear_item,const RsFileHash& hash,RsTurtleGenericDataItem *& encrypted_item);
bool decryptItem(RsTurtleGenericDataItem *encrypted_item, const RsFileHash& hash, RsTurtleGenericTunnelItem *&decrypted_item);
bool decryptItem(const RsTurtleGenericDataItem *encrypted_item, const RsFileHash& hash, RsTurtleGenericTunnelItem *&decrypted_item);
/*************** Internal Transfer Fns *************************/
virtual int tick();

View File

@ -482,7 +482,7 @@ void p3GRouter::handleLowLevelTransactionAckItem(RsGRouterTransactionAcknItem *t
#endif
}
void p3GRouter::receiveTurtleData(RsTurtleGenericTunnelItem *gitem, const RsFileHash &/*hash*/, const RsPeerId &virtual_peer_id, RsTurtleGenericTunnelItem::Direction /*direction*/)
void p3GRouter::receiveTurtleData(const RsTurtleGenericTunnelItem *gitem, const RsFileHash &/*hash*/, const RsPeerId &virtual_peer_id, RsTurtleGenericTunnelItem::Direction /*direction*/)
{
#ifdef GROUTER_DEBUG
std::cerr << "p3GRouter::receiveTurtleData() " << std::endl;
@ -496,7 +496,7 @@ void p3GRouter::receiveTurtleData(RsTurtleGenericTunnelItem *gitem, const RsFile
// - possibly packs multi-item blocks back together
// - converts it into a grouter generic item (by deserialising it)
RsTurtleGenericDataItem *item = dynamic_cast<RsTurtleGenericDataItem*>(gitem) ;
const RsTurtleGenericDataItem *item = dynamic_cast<const RsTurtleGenericDataItem*>(gitem) ;
if(item == NULL)
{
@ -510,7 +510,8 @@ void p3GRouter::receiveTurtleData(RsTurtleGenericTunnelItem *gitem, const RsFile
// Items come out of the pipe in order. We need to recover all chunks before we de-serialise the content and have it handled by handleIncoming()
RsItem *itm = RsGRouterSerialiser().deserialise(item->data_bytes,&item->data_size) ;
uint32_t size = item->data_size ;
RsItem *itm = RsGRouterSerialiser().deserialise(item->data_bytes,&size);
if(itm == NULL)
{

View File

@ -208,8 +208,9 @@ protected:
// Interaction with turtle router //
//===================================================//
uint16_t serviceId() const { return RS_SERVICE_TYPE_GROUTER; }
virtual bool handleTunnelRequest(const RsFileHash& /*hash*/,const RsPeerId& /*peer_id*/) ;
virtual void receiveTurtleData(RsTurtleGenericTunnelItem */*item*/,const RsFileHash& /*hash*/,const RsPeerId& /*virtual_peer_id*/,RsTurtleGenericTunnelItem::Direction /*direction*/);
virtual void receiveTurtleData(const RsTurtleGenericTunnelItem */*item*/,const RsFileHash& /*hash*/,const RsPeerId& /*virtual_peer_id*/,RsTurtleGenericTunnelItem::Direction /*direction*/);
virtual void addVirtualPeer(const TurtleFileHash& hash,const TurtleVirtualPeerId& virtual_peer_id,RsTurtleGenericTunnelItem::Direction dir) ;
virtual void removeVirtualPeer(const TurtleFileHash& hash,const TurtleVirtualPeerId& virtual_peer_id) ;

View File

@ -64,7 +64,7 @@ static const uint32_t INDEX_AUTHEN_ADMIN = 0x00000040; // admin key
#define GXS_MASK "GXS_MASK_HACK"
//#define GEN_EXCH_DEBUG 1
#define GEN_EXCH_DEBUG 1
static const uint32_t MSG_CLEANUP_PERIOD = 60*59; // 59 minutes
static const uint32_t INTEGRITY_CHECK_PERIOD = 60*31; // 31 minutes
@ -1110,6 +1110,8 @@ void RsGenExchange::receiveChanges(std::vector<RsGxsNotify*>& changes)
RsGxsNotify* n = *vit;
RsGxsGroupChange* gc;
RsGxsMsgChange* mc;
RsGxsDistantSearchResultChange *gt;
if((mc = dynamic_cast<RsGxsMsgChange*>(n)) != NULL)
{
if (mc->metaChange())
@ -1132,6 +1134,10 @@ void RsGenExchange::receiveChanges(std::vector<RsGxsNotify*>& changes)
out.mGrps.splice(out.mGrps.end(), gc->mGrpIdList);
}
}
else if((gt = dynamic_cast<RsGxsDistantSearchResultChange*>(n)) != NULL)
{
out.mDistantSearchReqs.push_back(gt->mRequestId);
}
else
std::cerr << "(EE) Unknown changes type!!" << std::endl;
@ -1567,7 +1573,7 @@ bool RsGenExchange::setAuthenPolicyFlag(const uint8_t &msgFlag, uint32_t& authen
return true;
}
void RsGenExchange::notifyNewGroups(std::vector<RsNxsGrp *> &groups)
void RsGenExchange::receiveNewGroups(std::vector<RsNxsGrp *> &groups)
{
RS_STACK_MUTEX(mGenMtx) ;
@ -1599,7 +1605,7 @@ void RsGenExchange::notifyNewGroups(std::vector<RsNxsGrp *> &groups)
}
void RsGenExchange::notifyNewMessages(std::vector<RsNxsMsg *>& messages)
void RsGenExchange::receiveNewMessages(std::vector<RsNxsMsg *>& messages)
{
RS_STACK_MUTEX(mGenMtx) ;
@ -1635,11 +1641,20 @@ void RsGenExchange::notifyNewMessages(std::vector<RsNxsMsg *>& messages)
}
}
void RsGenExchange::receiveDistantSearchResults(TurtleRequestId id,const RsGxsGroupId &grpId)
{
RS_STACK_MUTEX(mGenMtx);
RsGxsDistantSearchResultChange* gc = new RsGxsDistantSearchResultChange(id,grpId);
mNotifications.push_back(gc);
std::cerr << "RsGenExchange::receiveDistantSearchResults(): received result for request " << std::hex << id << std::dec << std::endl;
}
void RsGenExchange::notifyReceivePublishKey(const RsGxsGroupId &grpId)
{
RS_STACK_MUTEX(mGenMtx);
RsGxsGroupChange* gc = new RsGxsGroupChange(RsGxsNotify::TYPE_PUBLISHKEY, true);
RsGxsGroupChange* gc = new RsGxsGroupChange(RsGxsNotify::TYPE_RECEIVED_PUBLISHKEY, true);
gc->mGrpIdList.push_back(grpId);
mNotifications.push_back(gc);
}
@ -2310,7 +2325,7 @@ void RsGenExchange::publishMsgs()
if(!msgChangeMap.empty())
{
RsGxsMsgChange* ch = new RsGxsMsgChange(RsGxsNotify::TYPE_PUBLISH, false);
RsGxsMsgChange* ch = new RsGxsMsgChange(RsGxsNotify::TYPE_PUBLISHED, false);
ch->msgChangeMap = msgChangeMap;
mNotifications.push_back(ch);
}
@ -2447,7 +2462,7 @@ void RsGenExchange::processGroupDelete()
if(!grpDeleted.empty())
{
RsGxsGroupChange* gc = new RsGxsGroupChange(RsGxsNotify::TYPE_PUBLISH, false);
RsGxsGroupChange* gc = new RsGxsGroupChange(RsGxsNotify::TYPE_PUBLISHED, false);
gc->mGrpIdList = grpDeleted;
mNotifications.push_back(gc);
}
@ -2756,7 +2771,7 @@ void RsGenExchange::publishGrps()
if(!grpChanged.empty())
{
RsGxsGroupChange* gc = new RsGxsGroupChange(RsGxsNotify::TYPE_RECEIVE, true);
RsGxsGroupChange* gc = new RsGxsGroupChange(RsGxsNotify::TYPE_RECEIVED_NEW, true);
gc->mGrpIdList = grpChanged;
mNotifications.push_back(gc);
#ifdef GEN_EXCH_DEBUG
@ -3022,7 +3037,7 @@ void RsGenExchange::processRecvdMessages()
#endif
mDataStore->storeMessage(msgs_to_store);
RsGxsMsgChange* c = new RsGxsMsgChange(RsGxsNotify::TYPE_RECEIVE, false);
RsGxsMsgChange* c = new RsGxsMsgChange(RsGxsNotify::TYPE_RECEIVED_NEW, false);
c->msgChangeMap = msgIds;
mNotifications.push_back(c);
}
@ -3155,7 +3170,7 @@ void RsGenExchange::processRecvdGroups()
if(!grpIds.empty())
{
RsGxsGroupChange* c = new RsGxsGroupChange(RsGxsNotify::TYPE_RECEIVE, false);
RsGxsGroupChange* c = new RsGxsGroupChange(RsGxsNotify::TYPE_RECEIVED_NEW, false);
c->mGrpIdList = grpIds;
mNotifications.push_back(c);
mDataStore->storeGroup(grps_to_store);
@ -3239,7 +3254,7 @@ void RsGenExchange::performUpdateValidation()
}
// notify the client
RsGxsGroupChange* c = new RsGxsGroupChange(RsGxsNotify::TYPE_RECEIVE, true);
RsGxsGroupChange* c = new RsGxsGroupChange(RsGxsNotify::TYPE_RECEIVED_NEW, true);
for(uint32_t i=0;i<mGroupUpdates.size();++i)
if(mGroupUpdates[i].newGrp != NULL)
@ -3335,11 +3350,11 @@ void RsGenExchange::removeDeleteExistingMessages( std::list<RsNxsMsg*>& msgs, Gx
mDataStore->retrieveMsgIds(*it, msgIdReq[*it]);
#ifdef GEN_EXCH_DEBUG
const std::vector<RsGxsMessageId>& vec(msgIdReq[*it]) ;
const std::set<RsGxsMessageId>& vec(msgIdReq[*it]) ;
std::cerr << " retrieved " << vec.size() << " message ids for group " << *it << std::endl;
for(uint32_t i=0;i<vec.size();++i)
std::cerr << " " << vec[i] << std::endl;
for(auto it2(vec.begin());it2!=vec.end();++it2)
std::cerr << " " << *it2 << std::endl;
#endif
}
@ -3381,3 +3396,11 @@ void RsGenExchange::removeDeleteExistingMessages( std::list<RsNxsMsg*>& msgs, Gx
}
}
void RsGenExchange::turtleGroupRequest(const RsGxsGroupId& group_id)
{
mNetService->turtleGroupRequest(group_id) ;
}
void RsGenExchange::turtleSearchRequest(const std::string& match_string)
{
mNetService->turtleSearchRequest(match_string) ;
}

View File

@ -121,9 +121,9 @@ public:
virtual ~RsGenExchange();
// Convention that this is implemented here.
// Convention that this is implemented here.
// and passes to network service.
virtual RsServiceInfo getServiceInfo() = 0;
virtual RsServiceInfo getServiceInfo() = 0;
void setNetworkExchangeService(RsNetworkExchangeService *ns) ;
@ -132,18 +132,24 @@ public:
/*!
* @param messages messages are deleted after function returns
*/
virtual void notifyNewMessages(std::vector<RsNxsMsg*>& messages);
virtual void receiveNewMessages(std::vector<RsNxsMsg*>& messages);
/*!
* @param groups groups are deleted after function returns
*/
virtual void notifyNewGroups(std::vector<RsNxsGrp*>& groups);
virtual void receiveNewGroups(std::vector<RsNxsGrp*>& groups);
/*!
* @param grpId group id
*/
virtual void notifyReceivePublishKey(const RsGxsGroupId &grpId);
/*!
* \brief notifyReceiveDistantSearchResults
* Should be called when new search results arrive.
* \param grpId
*/
virtual void receiveDistantSearchResults(TurtleRequestId id,const RsGxsGroupId &grpId);
/*!
* @param grpId group id
*/
@ -287,6 +293,15 @@ public:
*/
bool getGroupStatistic(const uint32_t& token, GxsGroupStatistic& stats);
/*!
* \brief turtleGroupRequest
* Issues a browadcast group request using the turtle router generic search system. The request is obviously asynchroneous and will be
* handled in RsGenExchange when received.
* \param group_id
*/
void turtleGroupRequest(const RsGxsGroupId& group_id);
void turtleSearchRequest(const std::string& match_string);
protected:
bool messagePublicationTest(const RsGxsMsgMetaData&) ;
@ -566,7 +581,7 @@ public:
* @param msgs
*/
void deleteMsgs(uint32_t& token, const GxsMsgReq& msgs);
protected:
/*!
* This represents the group before its signature is calculated
@ -650,7 +665,7 @@ public:
*/
void shareGroupPublishKey(const RsGxsGroupId& grpId,const std::set<RsPeerId>& peers) ;
/*!
* Returns the local TS of the group as known by the network service.
* This is useful to allow various network services to sync their update TS
@ -755,6 +770,8 @@ protected:
*/
int createMessage(RsNxsMsg* msg);
RsNetworkExchangeService *netService() const { return mNetService ; }
private:
/*!
* convenience function to create sign

View File

@ -1807,6 +1807,23 @@ bool RsGxsDataAccess::updateGroupData(RsNxsGrp* grp) {
return mDataStore->updateGroup(grpM);
}
bool RsGxsDataAccess::getGroupData(const RsGxsGroupId& grpId, RsNxsGrp *& grp_data)
{
RsStackMutex stack(mDataMutex);
std::map<RsGxsGroupId, RsNxsGrp*> grps ;
grps[grpId] = NULL ;
if(mDataStore->retrieveNxsGrps(grps, false, true)) // the false here is very important: it removes the private key parts.
{
grp_data = grps.begin()->second;
return true;
}
else
return false ;
}
bool RsGxsDataAccess::addMsgData(RsNxsMsg* msg) {
RsStackMutex stack(mDataMutex);

View File

@ -156,6 +156,14 @@ public:
*/
bool addMsgData(RsNxsMsg* msg);
/*!
* This retrieves a group from the gxs data base, this is a blocking call \n
* @param grp the group to add, memory ownership passed to the callee
* @return false if group cound not be retrieved
*/
bool getGroupData(const RsGxsGroupId& grpId,RsNxsGrp *& grp_data);
public:

View File

@ -166,8 +166,6 @@
// | |
// (Only send if rand() < sendingProb()) +---comes from mClientMsgUpdateMap -----+
//
//
//
// Suggestions
// ===========
// * handleRecvSyncGroup should use mit->second.mLastPost to limit the sending of already known data
@ -194,6 +192,53 @@
// Problem: without msg, we cannot know the grpId!!
//
// * mClientMsgUpdateMap[peerid][grpId] is only updated when new msgs are received. Up to date groups will keep asking for lists!
//
// Distant sync
// ============
//
// Distant sync uses tunnels to sync subscribed GXS groups that are not supplied by friends. Peers can subscribe to a GXS group using a RS link
// which GXS uses to request updates through tunnels.
// * The whole exchange should be kept private and anonymous between the two distant peers, so we use the same trick than for FT: encrypt the data using the group ID.
// * The same node shouldn't be known as a common server for different GXS groups
//
// GXS net service:
// * talks to virtual peers, treated like normal peers
// * virtual peers only depend on the server ID, not on tunnel ID, and be kept constant accross time so that ClientGroupUpdateMap is kept consistent
// * does not use tunnels if friends can already supply the data (??) This causes issues with "islands".
//
// Tunnels:
// * a specific service named GxsSyncTunnelService handles the creation/management of sync tunnels:
// * tunnel data need to be encrypted.
//
// bool manageTunnels(const RsGxsGroupId&) ; // start managing tunnels for this group
// bool releaseTunnels(const RsGxsGroupId&) ; // stop managing tunnels for this group
// bool sendData(const unsigned char *data,uint32_t size,const RsPeerId& virtual_peer) ; // send data to this virtual peer
// bool getVirtualPeers(const RsGxsGroupId&, std::list<RsPeerId>& peers) ; // returns the virtual peers for this group
//
// Proposed protocol:
// * request tunnels based on H(GroupId)
// * encrypt tunnel data using chacha20+HMAC-SHA256 using AEAD( GroupId, 96bits IV, tunnel ID ) (similar to what FT does)
// * when tunnel is established, exchange virtual peer names: vpid = H( GroupID | Random bias )
// * when vpid is known, notify the client (GXS net service) which can use the virtual peer to sync
//
// * only use a single tunnel per virtual peer ID
//
// Client ------------------ TR(H(GroupId)) --------------> Server
//
// Client <-------------------- T OK ---------------------- Server
//
// [Encrypted traffic using H(GroupId, 96bits IV, tunnel ID)]
//
// Client <--------- VPID = H( Random IV | GroupId ) ------ Server
// | |
// +--------------> Mark the virtual peer active <-----------+
//
// Unsolved problems:
// * if we want to preserve anonymity, we cannot prevent GXS from duplicating the data from virtual/real peers that actually are the same peers.
// * ultimately we should only use tunnels to sync GXS. The mix between tunnels and real peers is not a problem but will cause unnecessary traffic.
//
// Notes:
// * given that GXS only talks to peers once every 2 mins, it's likely that keep-alive packets will be needed
#include <unistd.h>
@ -209,6 +254,7 @@
#include "retroshare/rsgxscircles.h"
#include "retroshare/rspeers.h"
#include "pgp/pgpauxutils.h"
#include "crypto/rscrypto.h"
#include "util/rsdir.h"
#include "util/rstime.h"
#include "util/rsmemory.h"
@ -224,6 +270,7 @@
NXS_NET_DEBUG_5 summary of transactions (useful to just know what comes in/out)
NXS_NET_DEBUG_6 group sync statistics (e.g. number of posts at nighbour nodes, etc)
NXS_NET_DEBUG_7 encryption/decryption of transactions
NXS_NET_DEBUG_8 gxs distant sync
***/
//#define NXS_NET_DEBUG_0 1
@ -234,6 +281,7 @@
//#define NXS_NET_DEBUG_5 1
//#define NXS_NET_DEBUG_6 1
//#define NXS_NET_DEBUG_7 1
#define NXS_NET_DEBUG_8 1
//#define NXS_FRAG
@ -256,6 +304,7 @@ static const uint32_t REJECTED_MESSAGE_RETRY_DELAY = 24*3600; //
static const uint32_t GROUP_STATS_UPDATE_DELAY = 240; // update unsubscribed group statistics every 3 mins
static const uint32_t GROUP_STATS_UPDATE_NB_PEERS = 2; // number of peers to which the group stats are asked
static const uint32_t MAX_ALLOWED_GXS_MESSAGE_SIZE = 199000; // 200,000 bytes including signature and headers
static const uint32_t MIN_DELAY_BETWEEN_GROUP_SEARCH = 40; // dont search same group more than every 40 secs.
static const uint32_t RS_NXS_ITEM_ENCRYPTION_STATUS_UNKNOWN = 0x00 ;
static const uint32_t RS_NXS_ITEM_ENCRYPTION_STATUS_NO_ERROR = 0x01 ;
@ -267,11 +316,12 @@ static const uint32_t RS_NXS_ITEM_ENCRYPTION_STATUS_GXS_KEY_MISSING = 0x05 ;
// Debug system to allow to print only for some IDs (group, Peer, etc)
#if defined(NXS_NET_DEBUG_0) || defined(NXS_NET_DEBUG_1) || defined(NXS_NET_DEBUG_2) || defined(NXS_NET_DEBUG_3) \
|| defined(NXS_NET_DEBUG_4) || defined(NXS_NET_DEBUG_5) || defined(NXS_NET_DEBUG_6) || defined(NXS_NET_DEBUG_7)
|| defined(NXS_NET_DEBUG_4) || defined(NXS_NET_DEBUG_5) || defined(NXS_NET_DEBUG_6) || defined(NXS_NET_DEBUG_7) \
|| defined(NXS_NET_DEBUG_8)
static const RsPeerId peer_to_print = RsPeerId(std::string("")) ;
static const RsGxsGroupId group_id_to_print = RsGxsGroupId(std::string("")) ; // use this to allow to this group id only, or "" for all IDs
static const uint32_t service_to_print = RS_SERVICE_TYPE_GXS_TRANS ; // use this to allow to this service id only, or 0 for all services
static const uint32_t service_to_print = RS_SERVICE_GXS_TYPE_CHANNELS ; // use this to allow to this service id only, or 0 for all services
// warning. Numbers should be SERVICE IDS (see serialiser/rsserviceids.h. E.g. 0x0215 for forums)
class nullstream: public std::ostream {};
@ -288,7 +338,6 @@ static std::string nice_time_stamp(time_t now,time_t TS)
}
}
static std::ostream& gxsnetdebug(const RsPeerId& peer_id,const RsGxsGroupId& grp_id,uint32_t service_type)
{
static nullstream null ;
@ -314,7 +363,8 @@ RsGxsNetService::RsGxsNetService(uint16_t servType, RsGeneralDataService *gds,
RsNxsNetMgr *netMgr, RsNxsObserver *nxsObs,
const RsServiceInfo serviceInfo,
RsGixsReputation* reputations, RsGcxs* circles, RsGixs *gixs,
PgpAuxUtils *pgpUtils, bool grpAutoSync, bool msgAutoSync, uint32_t default_store_period, uint32_t default_sync_period)
PgpAuxUtils *pgpUtils, RsGxsNetTunnelService *mGxsNT,
bool grpAutoSync, bool msgAutoSync, bool distSync, uint32_t default_store_period, uint32_t default_sync_period)
: p3ThreadedService(), p3Config(), mTransactionN(0),
mObserver(nxsObs), mDataStore(gds),
mServType(servType), mTransactionTimeOut(TRANSAC_TIMEOUT),
@ -322,8 +372,8 @@ RsGxsNetService::RsGxsNetService(uint16_t servType, RsGeneralDataService *gds,
mSyncTs(0), mLastKeyPublishTs(0),
mLastCleanRejectedMessages(0), mSYNC_PERIOD(SYNC_PERIOD),
mCircles(circles), mGixs(gixs),
mReputations(reputations), mPgpUtils(pgpUtils),
mGrpAutoSync(grpAutoSync), mAllowMsgSync(msgAutoSync),
mReputations(reputations), mPgpUtils(pgpUtils), mGxsNetTunnel(mGxsNT),
mGrpAutoSync(grpAutoSync), mAllowMsgSync(msgAutoSync),mAllowDistSync(distSync),
mServiceInfo(serviceInfo), mDefaultMsgStorePeriod(default_store_period),
mDefaultMsgSyncPeriod(default_sync_period)
{
@ -331,6 +381,8 @@ RsGxsNetService::RsGxsNetService(uint16_t servType, RsGeneralDataService *gds,
mOwnId = mNetMgr->getOwnId();
mUpdateCounter = 0;
mLastCacheReloadTS = 0;
// check the consistency
if(mDefaultMsgStorePeriod > 0 && mDefaultMsgSyncPeriod > mDefaultMsgStorePeriod)
@ -379,8 +431,7 @@ int RsGxsNetService::tick()
{
// always check for new items arriving
// from peers
if(receivedItems())
recvNxsItemQueue();
recvNxsItemQueue();
bool should_notify = false;
@ -403,6 +454,7 @@ int RsGxsNetService::tick()
{
syncWithPeers();
syncGrpStatistics();
checkDistantSyncState();
mSyncTs = now;
}
@ -450,8 +502,8 @@ void RsGxsNetService::processObserverNotifications()
mNewPublishKeysToNotify.clear() ;
}
if(!grps_copy.empty()) mObserver->notifyNewGroups (grps_copy);
if(!msgs_copy.empty()) mObserver->notifyNewMessages(msgs_copy);
if(!grps_copy.empty()) mObserver->receiveNewGroups (grps_copy);
if(!msgs_copy.empty()) mObserver->receiveNewMessages(msgs_copy);
for(std::set<RsGxsGroupId>::const_iterator it(keys_copy.begin());it!=keys_copy.end();++it)
mObserver->notifyReceivePublishKey(*it);
@ -520,6 +572,18 @@ void RsGxsNetService::syncWithPeers()
std::set<RsPeerId> peers;
mNetMgr->getOnlineList(mServiceInfo.mServiceType, peers);
if(mAllowDistSync && mGxsNetTunnel != NULL)
{
// Grab all online virtual peers of distant tunnels for the current service.
std::list<RsGxsNetTunnelVirtualPeerId> vpids ;
mGxsNetTunnel->getVirtualPeers(vpids);
for(auto it(vpids.begin());it!=vpids.end();++it)
peers.insert(RsPeerId(*it)) ;
}
if (peers.empty()) {
// nothing to do
return;
@ -549,7 +613,7 @@ void RsGxsNetService::syncWithPeers()
#ifdef NXS_NET_DEBUG_5
GXSNETDEBUG_P_(*sit) << "Service "<< std::hex << ((mServiceInfo.mServiceType >> 8)& 0xffff) << std::dec << " sending global group TS of peer id: " << *sit << " ts=" << nice_time_stamp(time(NULL),updateTS) << " (secs ago) to himself" << std::endl;
#endif
sendItem(grp);
generic_sendItem(grp);
}
if(!mAllowMsgSync)
@ -665,7 +729,7 @@ void RsGxsNetService::syncWithPeers()
#ifdef NXS_NET_DEBUG_7
GXSNETDEBUG_PG(*sit,grpId) << " Service " << std::hex << ((mServiceInfo.mServiceType >> 8)& 0xffff) << std::dec << " sending message TS of peer id: " << *sit << " ts=" << nice_time_stamp(time(NULL),updateTS) << " (secs ago) for group " << grpId << " to himself - in clear " << std::endl;
#endif
sendItem(msg);
generic_sendItem(msg);
#ifdef NXS_NET_DEBUG_5
GXSNETDEBUG_PG(*sit,grpId) << "Service "<< std::hex << ((mServiceInfo.mServiceType >> 8)& 0xffff) << std::dec << " sending global message TS of peer id: " << *sit << " ts=" << nice_time_stamp(time(NULL),updateTS) << " (secs ago) for group " << grpId << " to himself" << std::endl;
@ -676,6 +740,91 @@ void RsGxsNetService::syncWithPeers()
#endif
}
void RsGxsNetService::generic_sendItem(RsNxsItem *si)
{
// check if the item is to be sent to a distant peer or not
RsGxsGroupId tmp_grpId;
if(mAllowDistSync && mGxsNetTunnel != NULL && mGxsNetTunnel->isDistantPeer( static_cast<RsGxsNetTunnelVirtualPeerId>(si->PeerId()),tmp_grpId))
{
RsNxsSerialiser ser(mServType);
uint32_t size = ser.size(si);
unsigned char *mem = (unsigned char *)rs_malloc(size) ;
if(!mem)
return ;
#ifdef NXS_NET_DEBUG_8
GXSNETDEBUG_P_(si->PeerId()) << "Sending RsGxsNetTunnelService Item:" << (void*)si << " of type: " << std::hex << si->PacketId() << std::dec
<< " transaction " << si->transactionNumber << " to virtual peer " << si->PeerId() << std::endl ;
#endif
ser.serialise(si,mem,&size) ;
mGxsNetTunnel->sendTunnelData(mServType,mem,size,static_cast<RsGxsNetTunnelVirtualPeerId>(si->PeerId()));
}
else
sendItem(si) ;
}
void RsGxsNetService::checkDistantSyncState()
{
if(!mAllowDistSync || mGxsNetTunnel==NULL || !mGrpAutoSync)
return ;
RsGxsGrpMetaTemporaryMap grpMeta;
mDataStore->retrieveGxsGrpMetaData(grpMeta);
// Go through group statistics and groups without information are re-requested to random peers selected
// among the ones who provided the group info.
#ifdef NXS_NET_DEBUG_8
GXSNETDEBUG___<< "Checking distant sync for all groups." << std::endl;
#endif
// get the list of online peers
std::set<RsPeerId> online_peers;
mNetMgr->getOnlineList(mServiceInfo.mServiceType , online_peers);
RS_STACK_MUTEX(mNxsMutex) ;
for(auto it(grpMeta.begin());it!=grpMeta.end();++it)
if(it->second->mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_SUBSCRIBED) // we only consider subscribed groups here.
{
#warning (cyril) We might need to also remove peers for recently unsubscribed groups
const RsGxsGroupId& grpId(it->first);
const RsGxsGrpConfig& rec = locked_getGrpConfig(grpId) ;
#ifdef NXS_NET_DEBUG_6
GXSNETDEBUG__G(it->first) << " group " << grpId;
#endif
bool at_least_one_friend_is_supplier = false ;
for(auto it2(rec.suppliers.ids.begin());it2!=rec.suppliers.ids.end() && !at_least_one_friend_is_supplier;++it2)
if(online_peers.find(*it2) != online_peers.end()) // check that the peer is online
at_least_one_friend_is_supplier = true ;
// That strategy is likely to create islands of friends connected to each other. There's no real way
// to decide what to do here, except maybe checking the last message TS remotely vs. locally.
if(at_least_one_friend_is_supplier)
{
mGxsNetTunnel->releaseDistantPeers(mServType,grpId);
#ifdef NXS_NET_DEBUG_8
GXSNETDEBUG___<< " Group " << grpId << ": suppliers among friends. Releasing peers." << std::endl;
#endif
}
else
{
mGxsNetTunnel->requestDistantPeers(mServType,grpId);
#ifdef NXS_NET_DEBUG_8
GXSNETDEBUG___<< " Group " << grpId << ": no suppliers among friends. Requesting peers." << std::endl;
#endif
}
}
}
void RsGxsNetService::syncGrpStatistics()
{
RS_STACK_MUTEX(mNxsMutex) ;
@ -690,6 +839,17 @@ void RsGxsNetService::syncGrpStatistics()
std::set<RsPeerId> online_peers;
mNetMgr->getOnlineList(mServiceInfo.mServiceType, online_peers);
if(mAllowDistSync && mGxsNetTunnel != NULL)
{
// Grab all online virtual peers of distant tunnels for the current service.
std::list<RsGxsNetTunnelVirtualPeerId> vpids ;
mGxsNetTunnel->getVirtualPeers(vpids);
for(auto it(vpids.begin());it!=vpids.end();++it)
online_peers.insert(RsPeerId(*it)) ;
}
// Go through group statistics and groups without information are re-requested to random peers selected
// among the ones who provided the group info.
@ -704,44 +864,44 @@ void RsGxsNetService::syncGrpStatistics()
#endif
if(rec.statistics_update_TS + GROUP_STATS_UPDATE_DELAY < now && rec.suppliers.ids.size() > 0)
{
{
#ifdef NXS_NET_DEBUG_6
GXSNETDEBUG__G(it->first) << " needs update. Randomly asking to some friends" << std::endl;
GXSNETDEBUG__G(it->first) << " needs update. Randomly asking to some friends" << std::endl;
#endif
// randomly select GROUP_STATS_UPDATE_NB_PEERS friends among the suppliers of this group
// randomly select GROUP_STATS_UPDATE_NB_PEERS friends among the suppliers of this group
uint32_t n = RSRandom::random_u32() % rec.suppliers.ids.size() ;
uint32_t n = RSRandom::random_u32() % rec.suppliers.ids.size() ;
std::set<RsPeerId>::const_iterator rit = rec.suppliers.ids.begin();
for(uint32_t i=0;i<n;++i)
++rit ;
std::set<RsPeerId>::const_iterator rit = rec.suppliers.ids.begin();
for(uint32_t i=0;i<n;++i)
++rit ;
for(uint32_t i=0;i<std::min(rec.suppliers.ids.size(),(size_t)GROUP_STATS_UPDATE_NB_PEERS);++i)
{
// we started at a random position in the set, wrap around if the end is reached
if(rit == rec.suppliers.ids.end())
rit = rec.suppliers.ids.begin() ;
RsPeerId peer_id = *rit ;
++rit ;
if(online_peers.find(peer_id) != online_peers.end()) // check that the peer is online
for(uint32_t i=0;i<std::min(rec.suppliers.ids.size(),(size_t)GROUP_STATS_UPDATE_NB_PEERS);++i)
{
// we started at a random position in the set, wrap around if the end is reached
if(rit == rec.suppliers.ids.end())
rit = rec.suppliers.ids.begin() ;
RsPeerId peer_id = *rit ;
++rit ;
if(online_peers.find(peer_id) != online_peers.end()) // check that the peer is online
{
#ifdef NXS_NET_DEBUG_6
GXSNETDEBUG_PG(peer_id,it->first) << " asking friend " << peer_id << " for an update of stats for group " << it->first << std::endl;
GXSNETDEBUG_PG(peer_id,it->first) << " asking friend " << peer_id << " for an update of stats for group " << it->first << std::endl;
#endif
RsNxsSyncGrpStatsItem *grs = new RsNxsSyncGrpStatsItem(mServType) ;
RsNxsSyncGrpStatsItem *grs = new RsNxsSyncGrpStatsItem(mServType) ;
grs->request_type = RsNxsSyncGrpStatsItem::GROUP_INFO_TYPE_REQUEST ;
grs->request_type = RsNxsSyncGrpStatsItem::GROUP_INFO_TYPE_REQUEST ;
grs->grpId = it->first ;
grs->PeerId(peer_id) ;
grs->grpId = it->first ;
grs->PeerId(peer_id) ;
sendItem(grs) ;
generic_sendItem(grs) ;
}
}
}
}
}
#ifdef NXS_NET_DEBUG_6
else
GXSNETDEBUG__G(it->first) << " up to date." << std::endl;
@ -819,7 +979,7 @@ void RsGxsNetService::handleRecvSyncGrpStatistics(RsNxsSyncGrpStatsItem *grs)
GXSNETDEBUG_PG(grs->PeerId(),grs->grpId) << " sending back statistics item with " << vec.size() << " elements." << std::endl;
#endif
sendItem(grs_resp) ;
generic_sendItem(grs_resp) ;
}
else if(grs->request_type == RsNxsSyncGrpStatsItem::GROUP_INFO_TYPE_RESPONSE)
{
@ -1391,11 +1551,11 @@ public:
void operator() (RsItem* item)
{
RsGxsMsgUpdateItem* mui;
RsGxsGrpUpdateItem* gui;
RsGxsServerGrpUpdateItem* gsui;
RsGxsServerMsgUpdateItem* msui;
RsGxsGrpConfigItem* mgci;
RsGxsMsgUpdateItem *mui;
RsGxsGrpUpdateItem *gui;
RsGxsServerGrpUpdateItem *gsui;
RsGxsServerMsgUpdateItem *msui;
RsGxsGrpConfigItem *mgci;
if((mui = dynamic_cast<RsGxsMsgUpdateItem*>(item)) != NULL)
check_store(mui->peerID,mClientMsgMap,*mui);
@ -1421,7 +1581,6 @@ private:
RsGxsNetService::GrpConfigMap& mGrpConfigMap;
RsGxsServerGrpUpdate& mServerGrpUpdate;
};
bool RsGxsNetService::loadList(std::list<RsItem *> &load)
@ -1431,11 +1590,10 @@ bool RsGxsNetService::loadList(std::list<RsItem *> &load)
// The delete is done in StoreHere, if necessary
std::for_each(load.begin(), load.end(), StoreHere(mClientGrpUpdateMap, mClientMsgUpdateMap, mServerMsgUpdateMap, mServerGrpConfigMap, mGrpServerUpdate));
time_t now = time(NULL);
// We reset group statistics here. This is the best place since we know at this point which are all unsubscribed groups.
time_t now = time(NULL);
for(GrpConfigMap::iterator it(mServerGrpConfigMap.begin());it!=mServerGrpConfigMap.end();++it)
{
// At each reload, we reset the count of visible messages. It will be rapidely restored to its real value from friends.
@ -1489,6 +1647,7 @@ struct get_second : public std::unary_function<typename UpdateMap::value_type, R
typename UpdateMap::key_type ItemClass::*ID_member ;
};
bool RsGxsNetService::saveList(bool& cleanup, std::list<RsItem*>& save)
{
RS_STACK_MUTEX(mNxsMutex) ;
@ -1520,11 +1679,44 @@ RsSerialiser *RsGxsNetService::setupSerialiser()
return rss;
}
RsItem *RsGxsNetService::generic_recvItem()
{
{
RsItem *item ;
if(NULL != (item=recvItem()))
return item ;
}
unsigned char *data = NULL ;
uint32_t size = 0 ;
RsGxsNetTunnelVirtualPeerId virtual_peer_id ;
while(mAllowDistSync && mGxsNetTunnel!=NULL && mGxsNetTunnel->receiveTunnelData(mServType,data,size,virtual_peer_id))
{
RsNxsItem *item = dynamic_cast<RsNxsItem*>(RsNxsSerialiser(mServType).deserialise(data,&size)) ;
item->PeerId(virtual_peer_id) ;
free(data) ;
if(!item)
continue ;
#ifdef NXS_NET_DEBUG_8
GXSNETDEBUG_P_(item->PeerId()) << "Received RsGxsNetTunnelService Item:" << (void*)item << " of type: " << std::hex << item->PacketId() << std::dec
<< " transaction " << item->transactionNumber << " from virtual peer " << item->PeerId() << std::endl ;
#endif
return item ;
}
return NULL ;
}
void RsGxsNetService::recvNxsItemQueue()
{
RsItem *item ;
while(NULL != (item=recvItem()))
while(NULL != (item=generic_recvItem()))
{
#ifdef NXS_NET_DEBUG_1
GXSNETDEBUG_P_(item->PeerId()) << "Received RsGxsNetService Item:" << (void*)item << " type=" << std::hex << item->PacketId() << std::dec << std::endl ;
@ -1829,7 +2021,7 @@ void RsGxsNetService::debugDump()
GXSNETDEBUG___<< "RsGxsNetService::debugDump():" << std::endl;
RsGxsMetaDataTemporaryMap<RsGxsGrpMetaData> grpMetas;
RsGxsGrpMetaTemporaryMap grpMetas;
if(!group_id_to_print.isNull())
grpMetas[group_id_to_print] = NULL ;
@ -1842,7 +2034,7 @@ void RsGxsNetService::debugDump()
for(ServerMsgMap::const_iterator it(mServerMsgUpdateMap.begin());it!=mServerMsgUpdateMap.end();++it)
{
RsGxsMetaDataTemporaryMap<RsGxsGrpMetaData>::const_iterator it2 = grpMetas.find(it->first) ;
RsGxsGrpMetaTemporaryMap::const_iterator it2 = grpMetas.find(it->first) ;
RsGxsGrpMetaData *grpMeta = (it2 != grpMetas.end())? it2->second : NULL;
std::string subscribe_string = (grpMeta==NULL)?"Unknown" : ((grpMeta->mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_SUBSCRIBED)?" Subscribed":" NOT Subscribed") ;
@ -2125,7 +2317,7 @@ void RsGxsNetService::processTransactions()
lit_end = tr->mItems.end();
for(; lit != lit_end; ++lit){
sendItem(*lit);
generic_sendItem(*lit);
}
tr->mItems.clear(); // clear so they don't get deleted in trans cleaning
@ -2234,7 +2426,7 @@ void RsGxsNetService::processTransactions()
trans->transactFlag = RsNxsTransacItem::FLAG_END_SUCCESS;
trans->transactionNumber = transN;
trans->PeerId(tr->mTransaction->PeerId());
sendItem(trans);
generic_sendItem(trans);
// move to completed transactions
@ -2277,7 +2469,7 @@ void RsGxsNetService::processTransactions()
(tr->mTransaction->transactFlag & RsNxsTransacItem::FLAG_TYPE_MASK);
trans->transactionNumber = transN;
trans->PeerId(tr->mTransaction->PeerId());
sendItem(trans);
generic_sendItem(trans);
tr->mFlag = NxsTransaction::FLAG_STATE_RECEIVING;
}
@ -2654,7 +2846,7 @@ void RsGxsNetService::locked_pushMsgTransactionFromList(std::list<RsNxsItem*>& r
newTrans->mTransaction->PeerId(mOwnId);
if (locked_addTransaction(newTrans))
sendItem(transac);
generic_sendItem(transac);
else
{
delete newTrans;
@ -2950,7 +3142,7 @@ void RsGxsNetService::locked_pushGrpTransactionFromList( std::list<RsNxsItem*>&
newTrans->mTransaction->PeerId(mOwnId);
if (locked_addTransaction(newTrans))
sendItem(transac);
generic_sendItem(transac);
else
{
delete newTrans;
@ -3084,7 +3276,7 @@ void RsGxsNetService::locked_genSendGrpsTransaction(NxsTransaction* tr)
{
#ifdef NXS_NET_DEBUG_1
GXSNETDEBUG_P_(tr->mTransaction->PeerId()) << "locked_genSendGrpsTransaction() Generating Grp data send fron TransN: " << tr->mTransaction->transactionNumber << std::endl;
GXSNETDEBUG_P_(tr->mTransaction->PeerId()) << "locked_genSendGrpsTransaction() Generating Grp data send from TransN: " << tr->mTransaction->transactionNumber << std::endl;
#endif
// go groups requested in transaction tr
@ -3097,7 +3289,12 @@ void RsGxsNetService::locked_genSendGrpsTransaction(NxsTransaction* tr)
{
RsNxsSyncGrpItem* item = dynamic_cast<RsNxsSyncGrpItem*>(*lit);
if (item)
{
#ifdef NXS_NET_DEBUG_1
GXSNETDEBUG_PG(tr->mTransaction->PeerId(),item->grpId) << "locked_genSendGrpsTransaction() retrieving data for group \"" << item->grpId << "\"" << std::endl;
#endif
grps[item->grpId] = NULL;
}
else
{
#ifdef NXS_NET_DEBUG_1
@ -3109,7 +3306,12 @@ void RsGxsNetService::locked_genSendGrpsTransaction(NxsTransaction* tr)
if(!grps.empty())
mDataStore->retrieveNxsGrps(grps, false, false);
else
{
#ifdef NXS_NET_DEBUG_1
GXSNETDEBUG_P_(tr->mTransaction->PeerId()) << "RsGxsNetService::locked_genSendGrpsTransaction(): no group to request! This is unexpected" << std::endl;
#endif
return;
}
NxsTransaction* newTr = new NxsTransaction();
newTr->mFlag = NxsTransaction::FLAG_STATE_WAITING_CONFIRM;
@ -3126,6 +3328,9 @@ void RsGxsNetService::locked_genSendGrpsTransaction(NxsTransaction* tr)
mit->second->transactionNumber = transN;
newTr->mItems.push_back(mit->second);
mit->second = NULL ; // avoids deletion
#ifdef NXS_NET_DEBUG_1
GXSNETDEBUG_PG(tr->mTransaction->PeerId(),mit->first) << "RsGxsNetService::locked_genSendGrpsTransaction(): adding grp data of group \"" << mit->first << "\" to transaction" << std::endl;
#endif
}
if(newTr->mItems.empty()){
@ -3154,8 +3359,8 @@ void RsGxsNetService::locked_genSendGrpsTransaction(NxsTransaction* tr)
ntr->PeerId(tr->mTransaction->PeerId());
if(locked_addTransaction(newTr))
sendItem(ntr);
else
generic_sendItem(ntr);
else
{
delete ntr ;
delete newTr;
@ -3449,7 +3654,7 @@ void RsGxsNetService::locked_genSendMsgsTransaction(NxsTransaction* tr)
ntr->PeerId(tr->mTransaction->PeerId());
if(locked_addTransaction(newTr))
sendItem(ntr);
generic_sendItem(ntr);
else
{
delete ntr ;
@ -3768,7 +3973,7 @@ void RsGxsNetService::locked_pushGrpRespFromList(std::list<RsNxsItem*>& respList
<< peer << " with " << respList.size() << " groups " << std::endl;
#endif
if(locked_addTransaction(tr))
sendItem(trItem);
generic_sendItem(trItem);
else
{
delete tr ;
@ -3910,6 +4115,18 @@ bool RsGxsNetService::canSendGrpId(const RsPeerId& sslId, const RsGxsGrpMetaData
#ifdef NXS_NET_DEBUG_4
GXSNETDEBUG_PG(sslId,grpMeta.mGroupId) << "RsGxsNetService::canSendGrpId()"<< std::endl;
#endif
// check if that peer is a virtual peer id, in which case we only send/recv data to/from it items for the group it's requested for
RsGxsGroupId peer_grp ;
if(mAllowDistSync && mGxsNetTunnel != NULL && mGxsNetTunnel->isDistantPeer(RsGxsNetTunnelVirtualPeerId(sslId),peer_grp) && peer_grp != grpMeta.mGroupId)
{
#warning (cyril) make sure that this is not a problem for cross-service sending of items
#ifdef NXS_NET_DEBUG_4
GXSNETDEBUG_PG(sslId,grpMeta.mGroupId) << " Distant peer designed for group " << peer_grp << ": cannot request sync for different group." << std::endl;
#endif
return false ;
}
// first do the simple checks
uint8_t circleType = grpMeta.mCircleType;
@ -3963,6 +4180,17 @@ bool RsGxsNetService::checkCanRecvMsgFromPeer(const RsPeerId& sslId, const RsGxs
GXSNETDEBUG_PG(sslId,grpMeta.mGroupId) << "RsGxsNetService::checkCanRecvMsgFromPeer()";
GXSNETDEBUG_PG(sslId,grpMeta.mGroupId) << " peer Id = " << sslId << ", grpId=" << grpMeta.mGroupId <<std::endl;
#endif
// check if that peer is a virtual peer id, in which case we only send/recv data to/from it items for the group it's requested for
RsGxsGroupId peer_grp ;
if(mAllowDistSync && mGxsNetTunnel != NULL && mGxsNetTunnel->isDistantPeer(RsGxsNetTunnelVirtualPeerId(sslId),peer_grp) && peer_grp != grpMeta.mGroupId)
{
#ifdef NXS_NET_DEBUG_4
GXSNETDEBUG_PG(sslId,grpMeta.mGroupId) << " Distant peer designed for group " << peer_grp << ": cannot request sync for different group." << std::endl;
#endif
return false ;
}
// first do the simple checks
uint8_t circleType = grpMeta.mCircleType;
should_encrypt_id.clear() ;
@ -4293,7 +4521,7 @@ void RsGxsNetService::locked_pushMsgRespFromList(std::list<RsNxsItem*>& itemL, c
#endif
// signal peer to prepare for transaction
if(locked_addTransaction(tr))
sendItem(trItem);
generic_sendItem(trItem);
else
{
delete tr ;
@ -4306,6 +4534,16 @@ bool RsGxsNetService::canSendMsgIds(std::vector<RsGxsMsgMetaData*>& msgMetas, co
#ifdef NXS_NET_DEBUG_4
GXSNETDEBUG_PG(sslId,grpMeta.mGroupId) << "RsGxsNetService::canSendMsgIds() CIRCLE VETTING" << std::endl;
#endif
// check if that peer is a virtual peer id, in which case we only send/recv data to/from it items for the group it's requested for
RsGxsGroupId peer_grp ;
if(mAllowDistSync && mGxsNetTunnel != NULL && mGxsNetTunnel->isDistantPeer(RsGxsNetTunnelVirtualPeerId(sslId),peer_grp) && peer_grp != grpMeta.mGroupId)
{
#ifdef NXS_NET_DEBUG_4
GXSNETDEBUG_PG(sslId,grpMeta.mGroupId) << " Distant peer designed for group " << peer_grp << ": cannot request sync for different group." << std::endl;
#endif
return false ;
}
// first do the simple checks
uint8_t circleType = grpMeta.mCircleType;
@ -4546,7 +4784,7 @@ void RsGxsNetService::processExplicitGroupRequests()
for(; git != groupIdList.end(); ++git)
{
#ifdef NXS_NET_DEBUG_0
GXSNETDEBUG_PG(peerId,*git) << " group request for grp ID " << *git << " to peer " << peerId << std::endl;
GXSNETDEBUG_P_(peerId) << " group request for grp ID " << *git << " to peer " << peerId << std::endl;
#endif
RsNxsSyncGrpItem* item = new RsNxsSyncGrpItem(mServType);
item->grpId = *git;
@ -4680,7 +4918,7 @@ void RsGxsNetService::sharePublishKeysPending()
publishKeyItem->private_key = publishKey ;
publishKeyItem->PeerId(*it);
sendItem(publishKeyItem);
generic_sendItem(publishKeyItem);
#ifdef NXS_NET_DEBUG_3
GXSNETDEBUG_PG(*it,grpMeta->mGroupId) << " sent key item to " << *it << std::endl;
#endif
@ -4841,6 +5079,18 @@ bool RsGxsNetService::removeGroups(const std::list<RsGxsGroupId>& groups)
return true ;
}
bool RsGxsNetService::isDistantPeer(const RsPeerId& pid)
{
RS_STACK_MUTEX(mNxsMutex) ;
if(!mAllowDistSync || mGxsNetTunnel == NULL)
return false ;
RsGxsGroupId group_id ;
return mGxsNetTunnel->isDistantPeer(RsGxsNetTunnelVirtualPeerId(pid),group_id);
}
bool RsGxsNetService::stampMsgServerUpdateTS(const RsGxsGroupId& gid)
{
RS_STACK_MUTEX(mNxsMutex) ;
@ -4856,3 +5106,283 @@ bool RsGxsNetService::locked_stampMsgServerUpdateTS(const RsGxsGroupId& gid)
return true;
}
TurtleRequestId RsGxsNetService::turtleGroupRequest(const RsGxsGroupId& group_id)
{
RS_STACK_MUTEX(mNxsMutex) ;
time_t now = time(NULL);
auto it = mSearchedGroups.find(group_id) ;
if(mSearchedGroups.end() != it && (it->second.ts + MIN_DELAY_BETWEEN_GROUP_SEARCH > now))
{
std::cerr << "(WW) Last turtle request was " << now - it->second.ts << " secs ago. Not searching again." << std::endl;
return it->second.request_id;
}
#ifdef NXS_NET_DEBUG_8
GXSNETDEBUG__G(group_id) << " requesting group id " << group_id << " using turtle" << std::endl;
#endif
TurtleRequestId req = mGxsNetTunnel->turtleGroupRequest(group_id,this) ;
GroupRequestRecord& rec(mSearchedGroups[group_id]) ;
rec.request_id = req;
rec.ts = now;
mSearchRequests[req] = group_id;
return req;
}
TurtleRequestId RsGxsNetService::turtleSearchRequest(const std::string& match_string)
{
return mGxsNetTunnel->turtleSearchRequest(match_string,this) ;
}
static bool termSearch(const std::string& src, const std::string& substring)
{
/* always ignore case */
return src.end() != std::search( src.begin(), src.end(), substring.begin(), substring.end(), RsRegularExpression::CompareCharIC() );
}
bool RsGxsNetService::retrieveDistantSearchResults(TurtleRequestId req,std::map<RsGxsGroupId,RsGxsGroupSummary>& group_infos)
{
RS_STACK_MUTEX(mNxsMutex) ;
auto it = mDistantSearchResults.find(req) ;
if(it == mDistantSearchResults.end())
return false ;
group_infos = it->second;
return true ;
}
bool RsGxsNetService::retrieveDistantGroupSummary(const RsGxsGroupId& group_id,RsGxsGroupSummary& gs)
{
RS_STACK_MUTEX(mNxsMutex) ;
for(auto it(mDistantSearchResults.begin());it!=mDistantSearchResults.end();++it)
{
auto it2 = it->second.find(group_id) ;
if(it2 != it->second.end())
{
gs = it2->second;
return true ;
}
}
return false ;
}
bool RsGxsNetService::clearDistantSearchResults(const TurtleRequestId& id)
{
RS_STACK_MUTEX(mNxsMutex) ;
mDistantSearchResults.erase(id);
return true ;
}
void RsGxsNetService::receiveTurtleSearchResults(TurtleRequestId req, const std::list<RsGxsGroupSummary>& group_infos)
{
RS_STACK_MUTEX(mNxsMutex) ;
RsGxsGrpMetaTemporaryMap grpMeta;
std::map<RsGxsGroupId,RsGxsGroupSummary>& search_results_map(mDistantSearchResults[req]) ;
for(auto it(group_infos.begin());it!=group_infos.end();++it)
if(search_results_map.find((*it).group_id) == search_results_map.end())
grpMeta[(*it).group_id] = NULL;
mDataStore->retrieveGxsGrpMetaData(grpMeta);
std::list<RsGxsGroupSummary> filtered_results ;
// only keep groups that are not locally known, and groups that are not already in the mDistantSearchResults structure
for(auto it(group_infos.begin());it!=group_infos.end();++it)
if(grpMeta[(*it).group_id] == NULL)
{
filtered_results.push_back(*it) ;
auto it2 = search_results_map.find((*it).group_id) ;
if(it2 != search_results_map.end())
{
// update existing data
it2->second.popularity++ ;
it2->second.number_of_messages = std::max(it2->second.number_of_messages,(*it).number_of_messages) ;
}
else
{
search_results_map[(*it).group_id] = *it;
search_results_map[(*it).group_id].popularity = 1; // number of results so far
}
mObserver->receiveDistantSearchResults(req,(*it).group_id) ;
}
}
void RsGxsNetService::receiveTurtleSearchResults(TurtleRequestId req,const unsigned char *encrypted_group_data,uint32_t encrypted_group_data_len)
{
#ifdef NXS_NET_DEBUG_8
GXSNETDEBUG___ << " received encrypted group data for turtle search request " << std::hex << req << std::dec << ": " << RsUtil::BinToHex(encrypted_group_data,encrypted_group_data_len,50) << std::endl;
#endif
auto it = mSearchRequests.find(req);
if(mSearchRequests.end() == it)
{
std::cerr << "(EE) received search results for unknown request " << std::hex << req << std::dec ;
return;
}
RsGxsGroupId grpId = it->second;
uint8_t encryption_master_key[32];
Sha256CheckSum s = RsDirUtil::sha256sum(grpId.toByteArray(),grpId.SIZE_IN_BYTES);
memcpy(encryption_master_key,s.toByteArray(),32);
#ifdef NXS_NET_DEBUG_8
GXSNETDEBUG___ << " attempting data decryption with master key " << RsUtil::BinToHex(encryption_master_key,32) << std::endl;
#endif
unsigned char *clear_group_data = NULL;
uint32_t clear_group_data_len ;
if(!librs::crypto::decryptAuthenticateData(encrypted_group_data,encrypted_group_data_len,encryption_master_key,clear_group_data,clear_group_data_len))
{
std::cerr << "(EE) Could not decrypt data. Something went wrong. Wrong key??" << std::endl;
return ;
}
#ifdef NXS_NET_DEBUG_8
GXSNETDEBUG___ << " successfuly decrypted data : " << RsUtil::BinToHex(clear_group_data,clear_group_data_len,50) << std::endl;
#endif
RsItem *item = RsNxsSerialiser(mServType).deserialise(clear_group_data,&clear_group_data_len) ;
free(clear_group_data);
clear_group_data = NULL ;
RsNxsGrp *nxs_grp = dynamic_cast<RsNxsGrp*>(item) ;
if(nxs_grp == NULL)
{
std::cerr << "(EE) decrypted item is not a RsNxsGrp. Weird!" << std::endl;
return ;
}
std::vector<RsNxsGrp*> new_grps(1,nxs_grp);
#ifdef NXS_NET_DEBUG_8
GXSNETDEBUG___ << " passing the grp data to observer." << std::endl;
#endif
mObserver->receiveNewGroups(new_grps);
}
bool RsGxsNetService::search(const std::string& substring,std::list<RsGxsGroupSummary>& group_infos)
{
RsGxsGrpMetaTemporaryMap grpMetaMap;
{
RS_STACK_MUTEX(mNxsMutex) ;
mDataStore->retrieveGxsGrpMetaData(grpMetaMap);
}
RsGroupNetworkStats stats ;
for(auto it(grpMetaMap.begin());it!=grpMetaMap.end();++it)
if(termSearch(it->second->mGroupName,substring))
{
getGroupNetworkStats(it->first,stats) ;
RsGxsGroupSummary s ;
s.group_id = it->first ;
s.group_name = it->second->mGroupName ;
s.group_description = it->second->mGroupName ; // to be filled with something better when we use the real search
s.search_context = it->second->mGroupName ;
s.sign_flags = it->second->mSignFlags;
s.publish_ts = it->second->mPublishTs;
s.author_id = it->second->mAuthorId;
s.number_of_messages = stats.mMaxVisibleCount ;
s.last_message_ts = stats.mLastGroupModificationTS ;
s.popularity = it->second->mPop;
group_infos.push_back(s) ;
}
#ifdef NXS_NET_DEBUG_8
GXSNETDEBUG___ << " performing local substring search in response to distant request. Found " << group_infos.size() << " responses." << std::endl;
#endif
return !group_infos.empty();
}
bool RsGxsNetService::search(const Sha1CheckSum& hashed_group_id,unsigned char *& encrypted_group_data,uint32_t& encrypted_group_data_len)
{
// First look into the grp hash cache
#ifdef NXS_NET_DEBUG_8
GXSNETDEBUG___ << " Received group data request for hash " << hashed_group_id << std::endl;
#endif
auto it = mGroupHashCache.find(hashed_group_id) ;
RsNxsGrp *grp_data = NULL ;
if(mGroupHashCache.end() != it)
{
grp_data = it->second;
}
else
{
// Now check if the last request was too close in time, in which case, we dont retrieve data.
if(mLastCacheReloadTS + 60 > time(NULL))
{
std::cerr << "(WW) Not found in cache, and last cache reload less than 60 secs ago. Returning false. " << std::endl;
return false ;
}
#ifdef NXS_NET_DEBUG_8
GXSNETDEBUG___ << " reloading group cache information" << std::endl;
#endif
RsNxsGrpDataTemporaryMap grpDataMap;
{
RS_STACK_MUTEX(mNxsMutex) ;
mDataStore->retrieveNxsGrps(grpDataMap, true, true);
mLastCacheReloadTS = time(NULL);
}
for(auto it(grpDataMap.begin());it!=grpDataMap.end();++it)
if(it->second->metaData->mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_SUBSCRIBED ) // only cache subscribed groups
{
RsNxsGrp *grp = it->second ;
delete grp->metaData ; // clean private keys
grp->metaData = NULL ;
Sha1CheckSum hash(RsDirUtil::sha1sum(it->first.toByteArray(),it->first.SIZE_IN_BYTES));
mGroupHashCache[hash] = grp ;
it->second = NULL ; // prevents deletion
if(hash == hashed_group_id)
grp_data = grp ;
}
}
if(!grp_data)
{
#ifdef NXS_NET_DEBUG_8
GXSNETDEBUG___ << " no group found for hash " << hashed_group_id << ": returning false." << std::endl;
#endif
return false ;
}
#ifdef NXS_NET_DEBUG_8
GXSNETDEBUG___ << " found corresponding group data group id in cache group_id=" << grp_data->grpId << std::endl;
#endif
// Finally, serialize and encrypt the grp data
uint32_t size = RsNxsSerialiser(mServType).size(grp_data);
RsTemporaryMemory mem(size) ;
RsNxsSerialiser(mServType).serialise(grp_data,mem,&size) ;
uint8_t encryption_master_key[32];
Sha256CheckSum s = RsDirUtil::sha256sum(grp_data->grpId.toByteArray(),grp_data->grpId.SIZE_IN_BYTES);
memcpy(encryption_master_key,s.toByteArray(),32);
#ifdef NXS_NET_DEBUG_8
GXSNETDEBUG___ << " sending data encrypted with master key " << RsUtil::BinToHex(encryption_master_key,32) << std::endl;
#endif
return librs::crypto::encryptAuthenticateData(mem,size,encryption_master_key,encrypted_group_data,encrypted_group_data_len);
}

View File

@ -35,6 +35,7 @@
#include "pqi/p3linkmgr.h"
#include "rsitems/rsnxsitems.h"
#include "rsitems/rsgxsupdateitems.h"
#include "rsgxsnettunnel.h"
#include "rsgxsnetutils.h"
#include "pqi/p3cfgmgr.h"
#include "rsgixs.h"
@ -58,6 +59,14 @@ class RsGroupNetworkStatsRecord
time_t update_TS ;
};
struct GroupRequestRecord
{
GroupRequestRecord(): ts(0), request_id(0) {}
time_t ts ;
TurtleRequestId request_id;
};
/*!
* This class implements the RsNetWorkExchangeService
* using transactions to handle synchrnisation of Nxs items between
@ -89,8 +98,8 @@ public:
RsNxsObserver *nxsObs, // used to be = NULL.
const RsServiceInfo serviceInfo,
RsGixsReputation* reputations = NULL, RsGcxs* circles = NULL, RsGixs *gixs=NULL,
PgpAuxUtils *pgpUtils = NULL,
bool grpAutoSync = true, bool msgAutoSync = true,
PgpAuxUtils *pgpUtils = NULL, RsGxsNetTunnelService *mGxsNT = NULL,
bool grpAutoSync = true, bool msgAutoSync = true,bool distSync=false,
uint32_t default_store_period = RS_GXS_DEFAULT_MSG_STORE_PERIOD,
uint32_t default_sync_period = RS_GXS_DEFAULT_MSG_REQ_PERIOD);
@ -103,6 +112,8 @@ public:
public:
virtual uint16_t serviceType() const { return mServType ; }
/*!
* Use this to set how far back synchronisation and storage of messages should take place
* @param age the max age a sync/storage item can to be allowed in a synchronisation
@ -119,6 +130,23 @@ public:
virtual void setDefaultKeepAge(uint32_t t) { mDefaultMsgStorePeriod = t ; }
virtual void setDefaultSyncAge(uint32_t t) { mDefaultMsgSyncPeriod = t ; }
/*!
* \brief Search methods.
* These four methods are used to request distant search and receive the results.
* \param group_id
*/
virtual TurtleRequestId turtleGroupRequest(const RsGxsGroupId& group_id);
virtual TurtleRequestId turtleSearchRequest(const std::string& match_string);
virtual bool search(const std::string& substring,std::list<RsGxsGroupSummary>& group_infos) ;
virtual bool search(const Sha1CheckSum& hashed_group_id,unsigned char *& encrypted_group_data,uint32_t& encrypted_group_data_len);
virtual void receiveTurtleSearchResults(TurtleRequestId req,const std::list<RsGxsGroupSummary>& group_infos);
virtual void receiveTurtleSearchResults(TurtleRequestId req,const unsigned char *encrypted_group_data,uint32_t encrypted_group_data_len);
virtual bool retrieveDistantSearchResults(TurtleRequestId req, std::map<RsGxsGroupId, RsGxsGroupSummary> &group_infos);
virtual bool clearDistantSearchResults(const TurtleRequestId& id);
virtual bool retrieveDistantGroupSummary(const RsGxsGroupId&,RsGxsGroupSummary&);
/*!
* pauses synchronisation of subscribed groups and request for group id
* from peers
@ -167,6 +195,7 @@ public:
virtual bool getGroupServerUpdateTS(const RsGxsGroupId& gid,time_t& grp_server_update_TS,time_t& msg_server_update_TS) ;
virtual bool stampMsgServerUpdateTS(const RsGxsGroupId& gid) ;
virtual bool removeGroups(const std::list<RsGxsGroupId>& groups);
virtual bool isDistantPeer(const RsPeerId& pid);
/* p3Config methods */
public:
@ -394,6 +423,7 @@ private:
void locked_pushGrpRespFromList(std::list<RsNxsItem*>& respList, const RsPeerId& peer, const uint32_t& transN);
void locked_pushMsgRespFromList(std::list<RsNxsItem*>& itemL, const RsPeerId& sslId, const RsGxsGroupId &grp_id, const uint32_t& transN);
void checkDistantSyncState();
void syncWithPeers();
void syncGrpStatistics();
void addGroupItemToList(NxsTransaction*& tr,
@ -493,6 +523,9 @@ private:
void cleanRejectedMessages();
void processObserverNotifications();
void generic_sendItem(RsNxsItem *si);
RsItem *generic_recvItem();
private:
static void locked_checkDelay(uint32_t& time_in_secs);
@ -541,8 +574,11 @@ private:
RsGixs *mGixs;
RsGixsReputation* mReputations;
PgpAuxUtils *mPgpUtils;
RsGxsNetTunnelService *mGxsNetTunnel;
bool mGrpAutoSync;
bool mAllowMsgSync;
bool mAllowDistSync;
// need to be verfied
std::vector<AuthorPending*> mPendingResp;
@ -577,10 +613,18 @@ private:
std::set<RsGxsGroupId> mNewStatsToNotify ;
std::set<RsGxsGroupId> mNewPublishKeysToNotify ;
// Distant search result map
std::map<TurtleRequestId,std::map<RsGxsGroupId,RsGxsGroupSummary> > mDistantSearchResults ;
void debugDump();
uint32_t mDefaultMsgStorePeriod ;
uint32_t mDefaultMsgSyncPeriod ;
std::map<Sha1CheckSum, RsNxsGrp*> mGroupHashCache;
std::map<TurtleRequestId,RsGxsGroupId> mSearchRequests;
std::map<RsGxsGroupId,GroupRequestRecord> mSearchedGroups ;
time_t mLastCacheReloadTS ;
};
#endif // RSGXSNETSERVICE_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,277 @@
/*
* libretroshare/src/gxs: rsgxsnettunnel.h
*
* General Data service, interface for RetroShare.
*
* Copyright 2018-2018 by Cyril Soler
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License Version 2 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*
* Please report all bugs and problems to "retroshare.project@gmail.com"
*
*/
#pragma once
#include <map>
#include "turtle/p3turtle.h"
#include "retroshare/rsgxsdistsync.h"
/*!
* \brief The RsGxsNetTunnelService class takes care of requesting tunnels to the turtle router, through which it is possible to sync
* a particular GXS group. For each group, a set of virtual peers, corresponding to active tunnels will be made available
* to RsGxsNetService.
*
* It is the responsibility of RsGxsNetService to activate/desactivate tunnels for each particular group, depending on wether the group
* is already available at regular friends or not.
*
* Tunnel management is done at the level of groups rather than services, because we would like to keep the possibility to not
* request tunnels for some groups which do not need it, and only request tunnels for specific groups that cannot be provided
* by direct connections.
*/
// Protocol:
// * request tunnels based on H(GroupId)
// * encrypt tunnel data using chacha20+HMAC-SHA256 using AEAD( GroupId, 96bits IV, tunnel ID ) (similar to what FT does)
// * when tunnel is established, exchange virtual peer names: vpid = H( GroupID | Random bias )
// * when vpid is known, notify the client (GXS net service) which can use the virtual peer to sync
// * only use a single tunnel per virtual peer ID
// -
// Client ------------------ TR(H(GroupId)) --------------> Server |
// | Turtle
// Client <-------------------- T OK ---------------------- Server |
// -
// Here, a turtle vpid is known | [ addVirtualPeer() called by turtle ]
// -
// [Encrypted traffic using H(GroupId | Tunnel ID, 96bits IV)] |
// |
// Client <--------- VPID = H( Random IV | GroupId ) ------ Server |
// | | |
// +--------------> Mark the virtual peer active <-----------+ | Encrypted traffic decoded locally and sorted
// |
// Here, a consistent virtual peer ID is known |
// |
// Client <------------------- GXS Data ------------------> Server |
// -
// Notes:
// * tunnels are established symmetrically. If a distant peers wants to sync the same group, they'll have to open a single tunnel, with a different ID.
// Groups therefore have two states:
// - managed : the group can be used to answer tunnel requests. If server tunnels are established, the group will be synced with these peers
// - tunneled: the group will actively request tunnels. If tunnels are established both ways, the same virtual peers will be used so the tunnels are "merged".
// * In practice, that means one of the two tunnels will not be used and therefore die.
// * If a tunneled group already has enough virtual peers, it will not request for tunnels itself.
//
// Group policy | Request tunnels | SyncWithPeers | Item receipt
// --------------------+-------------------+-----------------------+----------------
// Passive | no | If peers present | If peers present
// Active | yes, if no peers | If peers present | If peers present
// | | |
//
// * when a service has the DistSync flag set, groups to sync are communicated passively to the GxsNetTunnel service when requesting distant peers.
// However, a call should be made to set a particular group policy to "ACTIVE" for group that do not have peers and need some.
//
// * services also need to retrieve GXS data items that come out of tunnels. These will be available as (data,len) type, since they are not de-serialized.
//
// * GxsNetService stores data information (such as update maps) per peerId, so it makes sense to use the same PeerId for all groups of a given service
// Therefore, virtual peers are stored separately from groups, because each one can sync multiple groups.
//
// * virtual peers are also shared among services. This reduces the required amount of tunnels and tunnel requests to send.
//
// * tunnels for a given service may also be used by the net service of p3IdService in order to explicitely request missing GxsIds.
// So GxsNetTunnel somehow allows different services to use the same tunnel. However we make sure that this traffic is limited to only p3IdService.
//
// How do we know that a group needs distant sync?
// * look into GrpConfigMap for suppliers. Suppliers is cleared at load.
// * last_update_TS in GrpConfigMap is randomised so it cannot be used
// * we need a way to know that there's no suppliers for good reasons (not that we just started)
//
// Security
// * the question of sync-ing with distant anonymous peers is a bit tricky because these peers can try to generate fake requests or change which messages are available
// and there is no way to prevent it. We therefore rely on GXS data integrity system to prevent this to happen.
//
class RsGxsNetTunnelItem ;
class RsNetworkExchangeService ;
class RsGxsNetTunnelService: public RsTurtleClientService, public RsTickingThread, public p3Config, public RsGxsDistSync
{
public:
RsGxsNetTunnelService() ;
virtual ~RsGxsNetTunnelService() ;
/*!
* \brief registerSearchableService
* Adds the network exchange service as a possible search source. This is used to allow distant search on the corresponding
* GXS service.
* \return
* always returns true.
*/
bool registerSearchableService(RsNetworkExchangeService *) ;
/*!
* \brief Manage tunnels for this group
* @param group_id group for which tunnels should be released
*/
bool requestDistantPeers(uint16_t service_id,const RsGxsGroupId&group_id) ;
/*!
* \brief Stop managing tunnels for this group
* @param group_id group for which tunnels should be released
*/
bool releaseDistantPeers(uint16_t service_id, const RsGxsGroupId&group_id) ;
/*!
* \brief Get the list of active virtual peers for a given group. This implies that a tunnel is up and
* alive. This function also "registers" the group which allows to handle tunnel requests in the server side.
*/
bool getVirtualPeers(std::list<RsGxsNetTunnelVirtualPeerId>& peers) ; // returns the virtual peers for this service
/*!
* \brief serviceId
* Overloads the method in RsTurtleClientService.
* \return
* The service id for RsGxsNetTunnel.
*/
uint16_t serviceId() const ;
/*!
* \brief sendData
* send data to this virtual peer, and takes memory ownership (deletes the item)
* \param item item to send
* \param virtual_peer destination virtual peer
* \return
* true if succeeded.
*/
bool sendTunnelData(uint16_t service_id,unsigned char *& data, uint32_t data_len, const RsGxsNetTunnelVirtualPeerId& virtual_peer) ;
/*!
* \brief receiveData
* returns the next piece of data received, and the virtual GXS peer that sended it.
* \param data memory check containing the data. Memory ownership belongs to the client.
* \param data_len length of memory chunk
* \param virtual_peer peer who sent the data
* \return
* true if something is returned. If not, data is set to NULL, data_len to 0.
*/
bool receiveTunnelData(uint16_t service_id, unsigned char *& data, uint32_t& data_len, RsGxsNetTunnelVirtualPeerId& virtual_peer) ;
/*!
* \brief isDistantPeer
* returns wether the peer is in the list of available distant peers or not
* \param group_id returned by the service to indicate which group this peer id is designed for.
* \return true if the peer is a distant GXS peer.
*/
bool isDistantPeer(const RsGxsNetTunnelVirtualPeerId& virtual_peer,RsGxsGroupId& group_id) ;
/*!
* \brief dumps all information about monitored groups.
*/
void dump() const;
/*!
* \brief connectToTurtleRouter
* Should be called after allocating a RsGxsNetTunnelService
* \param tr turtle router object
*/
virtual void connectToTurtleRouter(p3turtle *tr) ;
TurtleRequestId turtleGroupRequest(const RsGxsGroupId& group_id, RsNetworkExchangeService *client_service) ;
TurtleRequestId turtleSearchRequest(const std::string& match_string,RsNetworkExchangeService *client_service) ;
/*!
* \brief receiveSearchRequest
* See RsTurtleClientService::@
*/
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_allowed_hits);
virtual void receiveSearchResult(TurtleSearchRequestId request_id,unsigned char *search_result_data,uint32_t search_result_data_len);
// Overloaded from RsTickingThread
void data_tick() ;
// Overloads p3Config
RsSerialiser *setupSerialiser();
bool saveList(bool& cleanup, std::list<RsItem*>& save);
bool loadList(std::list<RsItem *> &load);
// Overloads RsGxsDistSync
void getStatistics(std::map<RsGxsGroupId,RsGxsNetTunnelGroupInfo>& groups, // groups on the client and server side
std::map<RsGxsNetTunnelVirtualPeerId, RsGxsNetTunnelVirtualPeerInfo>& virtual_peers, // current virtual peers, which group they provide, and how to talk to them through turtle
std::map<TurtleVirtualPeerId,RsGxsNetTunnelVirtualPeerId>& turtle_vpid_to_net_tunnel_vpid,
Bias20Bytes& bias) const;
protected:
// interaction with turtle router
virtual bool handleTunnelRequest(const RsFileHash &hash,const RsPeerId& peer_id) ;
virtual void receiveTurtleData(const RsTurtleGenericTunnelItem *item,const RsFileHash& hash,const RsPeerId& virtual_peer_id,RsTurtleGenericTunnelItem::Direction direction) ;
void addVirtualPeer(const TurtleFileHash&, const TurtleVirtualPeerId&,RsTurtleGenericTunnelItem::Direction dir) ;
void removeVirtualPeer(const TurtleFileHash&, const TurtleVirtualPeerId&) ;
const Bias20Bytes& locked_randomBias() ;
p3turtle *mTurtle ;
static const uint32_t RS_GXS_TUNNEL_CONST_RANDOM_BIAS_SIZE = 20 ;
static const uint32_t RS_GXS_TUNNEL_CONST_EKEY_SIZE = 32 ;
mutable Bias20Bytes mRandomBias ; // constant accross reboots. Allows to disguise the real SSL id while providing a consistent value accross time.
private:
void autowash() ;
void sendKeepAlivePackets() ;
void handleIncoming(RsGxsNetTunnelItem *item) ;
void flush_pending_items();
std::map<RsGxsGroupId,RsGxsNetTunnelGroupInfo> mGroups ; // groups on the client and server side
std::map<RsGxsNetTunnelVirtualPeerId, RsGxsNetTunnelVirtualPeerInfo> mVirtualPeers ; // current virtual peers, which group they provide, and how to talk to them through turtle
std::map<RsFileHash, RsGxsGroupId> mHandledHashes ; // hashes asked to turtle. Used to answer tunnel requests
std::map<TurtleVirtualPeerId, RsGxsNetTunnelVirtualPeerId> mTurtle2GxsPeer ; // convertion table to find GXS peer id from turtle
std::list<std::pair<TurtleVirtualPeerId,RsTurtleGenericDataItem*> > mPendingTurtleItems ; // items that need to be sent off-turtle Mutex.
std::map<uint16_t, std::list<std::pair<RsGxsNetTunnelVirtualPeerId,RsTlvBinaryData *> > > mIncomingData; // list of incoming data items
std::map<uint16_t,RsNetworkExchangeService *> mSearchableServices ;
/*!
* \brief Generates the hash to request tunnels for this group. This hash is only used by turtle, and is used to
* hide the real group id.
*/
RsFileHash calculateGroupHash(const RsGxsGroupId&group_id) const ;
/*!
* \brief makeVirtualPeerIdForGroup creates a virtual peer id that can be used and that will be constant accross time, whatever the
* tunnel ID and turtle virtual peer id. This allows RsGxsNetService to keep sync-ing the data consistently.
*/
RsGxsNetTunnelVirtualPeerId locked_makeVirtualPeerId(const RsGxsGroupId& group_id) ;
static void generateEncryptionKey(const RsGxsGroupId& group_id,const TurtleVirtualPeerId& vpid,unsigned char key[RS_GXS_TUNNEL_CONST_EKEY_SIZE]) ;
mutable RsMutex mGxsNetTunnelMtx;
friend class RsGxsTunnelRandomBiasItem ;
friend class StoreHere ;
time_t mLastKeepAlive ;
time_t mLastAutoWash ;
time_t mLastDump ;
};

View File

@ -36,6 +36,7 @@
#include "services/p3service.h"
#include "retroshare/rsreputations.h"
#include "retroshare/rsidentity.h"
#include "retroshare/rsturtle.h"
#include "rsgds.h"
/*!
@ -58,6 +59,7 @@
* 2 transfers only between group
* - the also group matrix settings which is by default everyone can transfer to each other
*/
class RsNetworkExchangeService
{
public:
@ -65,6 +67,7 @@ public:
RsNetworkExchangeService(){ return;}
virtual ~RsNetworkExchangeService() {}
virtual uint16_t serviceType() const =0;
/*!
* Use this to set how far back synchronisation of messages should take place
* @param age in seconds the max age a sync/store item can to be allowed in a synchronisation
@ -81,6 +84,65 @@ public:
virtual uint32_t getDefaultSyncAge() =0;
virtual uint32_t getDefaultKeepAge() =0;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// DISTANT SEARCH FUNCTIONS ///
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*!
* \brief turtleGroupRequest
* Requests a particular group meta data. The request protects the group ID.
* \param group_id
* \return
* returns the turtle request ID that might be associated to some results.
*/
virtual TurtleRequestId turtleGroupRequest(const RsGxsGroupId& group_id)=0;
/*!
* \brief turtleSearchRequest
* Uses distant search to match the substring to the group meta data.
* \param match_string
* \return
* returns the turtle request ID that might be associated to some results.
*/
virtual TurtleRequestId turtleSearchRequest(const std::string& match_string)=0;
/*!
* \brief receiveTurtleSearchResults
* Called by turtle (through RsGxsNetTunnel) when new results are received
* \param req Turtle search request ID associated with this result
* \param group_infos Group summary information for the groups returned by the search
*/
virtual void receiveTurtleSearchResults(TurtleRequestId req,const std::list<RsGxsGroupSummary>& group_infos)=0;
/*!
* \brief receiveTurtleSearchResults
* Called by turtle (through RsGxsNetTunnel) when new data is received
* \param req Turtle search request ID associated with this result
* \param encrypted_group_data Group data
*/
virtual void receiveTurtleSearchResults(TurtleRequestId req,const unsigned char *encrypted_group_data,uint32_t encrypted_group_data_len)=0;
/*!
* \brief retrieveTurtleSearchResults
* To be used to retrieve the search results that have been notified (or not)
* \param req request that match the results to retrieve
* \param group_infos results to retrieve.
* \return
* false when the request is unknown.
*/
virtual bool retrieveDistantSearchResults(TurtleRequestId req, std::map<RsGxsGroupId, RsGxsGroupSummary> &group_infos)=0;
/*!
* \brief getDistantSearchResults
* \param id
* \param group_infos
* \return
*/
virtual bool clearDistantSearchResults(const TurtleRequestId& id)=0;
virtual bool retrieveDistantGroupSummary(const RsGxsGroupId&,RsGxsGroupSummary&)=0;
virtual bool search(const std::string& substring,std::list<RsGxsGroupSummary>& group_infos) =0;
virtual bool search(const Sha1CheckSum& hashed_group_id,unsigned char *& encrypted_group_data,uint32_t& encrypted_group_data_len)=0;
/*!
* Initiates a search through the network
* This returns messages which contains the search terms set in RsGxsSearch
@ -99,6 +161,9 @@ public:
*/
//virtual int searchGrps(RsGxsSearch* search, uint8_t hops = 1, bool retrieve = 0) = 0;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// DATA ACCESS FUNCTIONS ///
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*!
* pauses synchronisation of subscribed groups and request for group id
@ -166,6 +231,14 @@ public:
*/
virtual bool stampMsgServerUpdateTS(const RsGxsGroupId& gid) =0;
/*!
* \brief isDistantPeer
* \param pid peer that is a virtual peer provided by GxsNetTunnel
* \return
* true if the peer exists (adn therefore is online)
*/
virtual bool isDistantPeer(const RsPeerId& pid)=0;
/*!
* \brief removeGroups
* Removes time stamp information from the list of groups. This allows to re-sync them if suppliers are present.

View File

@ -29,6 +29,7 @@
#include <set>
#include "rsitems/rsnxsitems.h"
typedef uint32_t TurtleRequestId ;
class RsNxsObserver
{
@ -42,12 +43,22 @@ public:
/*!
* @param messages messages are deleted after function returns
*/
virtual void notifyNewMessages(std::vector<RsNxsMsg*>& messages) = 0;
virtual void receiveNewMessages(std::vector<RsNxsMsg*>& messages) = 0;
/*!
* @param groups groups are deleted after function returns
*/
virtual void notifyNewGroups(std::vector<RsNxsGrp*>& groups) = 0;
virtual void receiveNewGroups(std::vector<RsNxsGrp*>& groups) = 0;
/*!
* \brief receiveDistantSearchResults
* Called when new distant search result arrive.
* \param grpId
*/
virtual void receiveDistantSearchResults(TurtleRequestId /*id*/,const RsGxsGroupId& /*grpId*/)
{
std::cerr << __PRETTY_FUNCTION__ << ": not overloaded but still called. Nothing will happen." << std::endl;
}
/*!
* @param grpId group id

View File

@ -839,7 +839,7 @@ bool p3GxsTrans::dispatchDecryptedMail( const RsGxsId& authorId,
#endif
std::vector<RsNxsMsg*> rcct; rcct.push_back(receipt);
RsGenExchange::notifyNewMessages(rcct);
RsGenExchange::receiveNewMessages(rcct);
GxsTransClient* recipientService = NULL;
{

View File

@ -685,7 +685,7 @@ void p3GxsTunnelService::removeVirtualPeer(const TurtleFileHash& hash,const Turt
}
}
void p3GxsTunnelService::receiveTurtleData(RsTurtleGenericTunnelItem *gitem,const RsFileHash& hash, const RsPeerId& virtual_peer_id,RsTurtleGenericTunnelItem::Direction direction)
void p3GxsTunnelService::receiveTurtleData(const RsTurtleGenericTunnelItem *gitem, const RsFileHash& hash, const RsPeerId& virtual_peer_id, RsTurtleGenericTunnelItem::Direction direction)
{
#ifdef DEBUG_GXS_TUNNEL
std::cerr << "GxsTunnelService::receiveTurtleData(): Received turtle data. " << std::endl;
@ -697,7 +697,7 @@ void p3GxsTunnelService::receiveTurtleData(RsTurtleGenericTunnelItem *gitem,cons
(void) direction;
#endif
RsTurtleGenericDataItem *item = dynamic_cast<RsTurtleGenericDataItem*>(gitem) ;
const RsTurtleGenericDataItem *item = dynamic_cast<const RsTurtleGenericDataItem*>(gitem) ;
if(item == NULL)
{

View File

@ -95,7 +95,7 @@
// by a mix between our own GXS id and the GXS id we're talking to. That is what the TunnelVirtualPeer is.
//
//
// RequestTunnel(source_own_id,destination_id) -
// RequestTunnel(source_own_id,destination_id) -
// | |
// +---------------------------> p3Turtle::monitorTunnels( hash(destination_id) ) |
// | |
@ -127,6 +127,8 @@ public:
explicit p3GxsTunnelService(RsGixs *pids) ;
virtual void connectToTurtleRouter(p3turtle *) ;
uint16_t serviceId() const { return RS_SERVICE_TYPE_GXS_TUNNEL ; }
// Creates the invite if the public key of the distant peer is available.
// Om success, stores the invite in the map above, so that we can respond to tunnel requests.
//
@ -211,7 +213,7 @@ private:
// Overloaded from RsTurtleClientService
virtual bool handleTunnelRequest(const RsFileHash &hash,const RsPeerId& peer_id) ;
virtual void receiveTurtleData(RsTurtleGenericTunnelItem *item,const RsFileHash& hash,const RsPeerId& virtual_peer_id,RsTurtleGenericTunnelItem::Direction direction) ;
virtual void receiveTurtleData(const RsTurtleGenericTunnelItem *item,const RsFileHash& hash,const RsPeerId& virtual_peer_id,RsTurtleGenericTunnelItem::Direction direction) ;
void addVirtualPeer(const TurtleFileHash&, const TurtleVirtualPeerId&,RsTurtleGenericTunnelItem::Direction dir) ;
void removeVirtualPeer(const TurtleFileHash&, const TurtleVirtualPeerId&) ;

View File

@ -137,6 +137,7 @@ PUBLIC_HEADERS = retroshare/rsdisc.h \
retroshare/rsconfig.h \
retroshare/rsversion.h \
retroshare/rsservicecontrol.h \
retroshare/rsgxsdistsync.h
HEADERS += plugins/pluginmanager.h \
plugins/dlfcn_win32.h \
@ -351,7 +352,8 @@ HEADERS += ft/ftchunkmap.h \
ft/ftturtlefiletransferitem.h
HEADERS += crypto/chacha20.h \
crypto/hashstream.h
crypto/hashstream.h \
crypto/rscrypto.h
HEADERS += directory_updater.h \
directory_list.h \
@ -519,7 +521,8 @@ SOURCES += ft/ftchunkmap.cc \
ft/ftturtlefiletransferitem.cc
SOURCES += crypto/chacha20.cpp \
crypto/hashstream.cc
crypto/hashstream.cc \
crypto/rscrypto.cpp
SOURCES += chat/distantchat.cc \
chat/p3chatservice.cc \
@ -707,6 +710,7 @@ HEADERS += rsitems/rsnxsitems.h \
gxs/rsgxs.h \
gxs/rsdataservice.h \
gxs/rsgxsnetservice.h \
gxs/rsgxsnettunnel.h \
retroshare/rsgxsflags.h \
retroshare/rsgxsifacetypes.h \
gxs/rsgenexchange.h \
@ -732,6 +736,7 @@ SOURCES += rsitems/rsnxsitems.cc \
gxs/rsdataservice.cc \
gxs/rsgenexchange.cc \
gxs/rsgxsnetservice.cc \
gxs/rsgxsnettunnel.cc \
gxs/rsgxsdata.cc \
rsitems/rsgxsitems.cc \
gxs/rsgxsdataaccess.cc \

View File

@ -65,7 +65,7 @@ void p3ConfigMgr::tick()
#ifdef CONFIG_DEBUG
std::cerr << "p3ConfigMgr::tick() Config Changed - Element: ";
std::cerr << it->first;
std::cerr << *it;
std::cerr << std::endl;
#endif
@ -111,7 +111,7 @@ void p3ConfigMgr::saveConfig()
{
#ifdef CONFIG_DEBUG
std::cerr << "p3ConfigMgr::globalSaveConfig() Saving Element: ";
std::cerr << it->first;
std::cerr << *it;
std::cerr << std::endl;
#endif
ok &= (*it)->saveConfiguration();
@ -137,7 +137,7 @@ void p3ConfigMgr::loadConfig()
{
#ifdef CONFIG_DEBUG
std::cerr << "p3ConfigMgr::loadConfig() Element: ";
std::cerr << cit->first <<"Dummy Hash: " << dummyHash;
std::cerr << *cit <<" Dummy Hash: " << dummyHash;
std::cerr << std::endl;
#endif

View File

@ -231,7 +231,9 @@ void p3Notify::notifyChatLobbyTimeShift (int time_shift)
void p3Notify::notifyCustomState (const std::string& peer_id , const std::string& status_string ) { FOR_ALL_NOTIFY_CLIENTS (*it)->notifyCustomState (peer_id,status_string) ; }
void p3Notify::notifyHashingInfo (uint32_t type , const std::string& fileinfo ) { FOR_ALL_NOTIFY_CLIENTS (*it)->notifyHashingInfo (type,fileinfo) ; }
void p3Notify::notifyTurtleSearchResult (uint32_t search_id , const std::list<TurtleFileInfo>& files ) { FOR_ALL_NOTIFY_CLIENTS (*it)->notifyTurtleSearchResult(search_id,files) ; }
void p3Notify::notifyPeerHasNewAvatar (std::string peer_id ) { FOR_ALL_NOTIFY_CLIENTS (*it)->notifyPeerHasNewAvatar(peer_id) ; }
#warning MISSING CODE HERE
//void p3Notify::notifyTurtleSearchResult (uint32_t search_id , const std::list<TurtleGxsInfo>& groups ) { FOR_ALL_NOTIFY_CLIENTS (*it)->notifyTurtleSearchResult(search_id,groups) ; }
void p3Notify::notifyPeerHasNewAvatar (std::string peer_id ) { FOR_ALL_NOTIFY_CLIENTS (*it)->notifyPeerHasNewAvatar(peer_id) ; }
void p3Notify::notifyOwnAvatarChanged () { FOR_ALL_NOTIFY_CLIENTS (*it)->notifyOwnAvatarChanged() ; }
void p3Notify::notifyOwnStatusMessageChanged() { FOR_ALL_NOTIFY_CLIENTS (*it)->notifyOwnStatusMessageChanged() ; }
void p3Notify::notifyDiskFull (uint32_t location , uint32_t size_limit_in_MB ) { FOR_ALL_NOTIFY_CLIENTS (*it)->notifyDiskFull (location,size_limit_in_MB) ; }

View File

@ -106,6 +106,8 @@ class p3Notify: public RsNotify
void notifyCustomState (const std::string& /* peer_id */, const std::string& /* status_string */) ;
void notifyHashingInfo (uint32_t /* type */, const std::string& /* fileinfo */) ;
void notifyTurtleSearchResult (uint32_t /* search_id */, const std::list<TurtleFileInfo>& /* files */) ;
#warning MISSING CODE HERE
// void notifyTurtleSearchResult (uint32_t /* search_id */, const std::list<TurtleGxsInfo >& /* groups */) ;
void notifyPeerHasNewAvatar (std::string /* peer_id */) ;
void notifyOwnAvatarChanged () ;
void notifyOwnStatusMessageChanged () ;

View File

@ -32,6 +32,7 @@
#include <string>
#include "rstypes.h"
#include "rsturtle.h"
class RsFiles;
extern RsFiles *rsFiles;
@ -212,6 +213,8 @@ public:
virtual uint32_t getMaxUploadSlotsPerFriend()=0;
virtual void setFilePermDirectDL(uint32_t perm)=0;
virtual uint32_t filePermDirectDL()=0;
virtual TurtleRequestId turtleSearch(const std::string& string_to_match) =0;
virtual TurtleRequestId turtleSearch(const RsRegularExpression::LinearizedExpression& expr) =0;
/***
* Control of Downloads Priority.

View File

@ -33,8 +33,7 @@
#include "retroshare/rstokenservice.h"
#include "retroshare/rsgxsifacehelper.h"
#include "retroshare/rsgxscommon.h"
#include "retroshare/rsturtle.h"
/* The Main Interface Class - for information about your Peers */
class RsGxsChannels;
@ -77,55 +76,49 @@ std::ostream &operator<<(std::ostream &out, const RsGxsChannelPost &post);
class RsGxsChannels: public RsGxsIfaceHelper, public RsGxsCommentService
{
public:
public:
explicit RsGxsChannels(RsGxsIface *gxs)
:RsGxsIfaceHelper(gxs) {}
:RsGxsIfaceHelper(gxs) {}
virtual ~RsGxsChannels() {}
/* Specific Service Data */
virtual bool getGroupData(const uint32_t &token, std::vector<RsGxsChannelGroup> &groups) = 0;
virtual bool getPostData(const uint32_t &token, std::vector<RsGxsChannelPost> &posts, std::vector<RsGxsComment> &cmts) = 0;
virtual bool getPostData(const uint32_t &token, std::vector<RsGxsChannelPost> &posts) = 0;
//Not currently used
//virtual bool getRelatedPosts(const uint32_t &token, std::vector<RsGxsChannelPost> &posts) = 0;
virtual bool getGroupData(const uint32_t &token, std::vector<RsGxsChannelGroup> &groups) = 0;
virtual bool getPostData(const uint32_t &token, std::vector<RsGxsChannelPost> &posts, std::vector<RsGxsComment> &cmts) = 0;
virtual bool getPostData(const uint32_t &token, std::vector<RsGxsChannelPost> &posts) = 0;
/* From RsGxsCommentService */
//virtual bool getCommentData(const uint32_t &token, std::vector<RsGxsComment> &comments) = 0;
//virtual bool getRelatedComments(const uint32_t &token, std::vector<RsGxsComment> &comments) = 0;
//virtual bool createComment(uint32_t &token, RsGxsComment &comment) = 0;
//virtual bool createVote(uint32_t &token, RsGxsVote &vote) = 0;
//////////////////////////////////////////////////////////////////////////////
/// Distant synchronisation methods ///
//////////////////////////////////////////////////////////////////////////////
///
virtual TurtleRequestId turtleGroupRequest(const RsGxsGroupId& group_id)=0;
virtual TurtleRequestId turtleSearchRequest(const std::string& match_string)=0;
virtual bool retrieveDistantSearchResults(TurtleRequestId req, std::map<RsGxsGroupId, RsGxsGroupSummary> &results) =0;
virtual bool clearDistantSearchResults(TurtleRequestId req)=0;
virtual bool retrieveDistantGroup(const RsGxsGroupId& group_id,RsGxsChannelGroup& distant_group)=0;
//////////////////////////////////////////////////////////////////////////////
virtual void setMessageReadStatus(uint32_t& token, const RsGxsGrpMsgIdPair& msgId, bool read) = 0;
//////////////////////////////////////////////////////////////////////////////
virtual void setMessageReadStatus(uint32_t& token, const RsGxsGrpMsgIdPair& msgId, bool read) = 0;
virtual bool setChannelAutoDownload(const RsGxsGroupId &groupId, bool enabled) = 0;
virtual bool getChannelAutoDownload(const RsGxsGroupId &groupid, bool& enabled) = 0;
virtual bool setChannelAutoDownload(const RsGxsGroupId &groupId, bool enabled) = 0;
virtual bool getChannelAutoDownload(const RsGxsGroupId &groupid, bool& enabled) = 0;
virtual bool setChannelDownloadDirectory(const RsGxsGroupId &groupId, const std::string& directory)=0;
virtual bool getChannelDownloadDirectory(const RsGxsGroupId &groupId, std::string& directory)=0;
virtual bool setChannelDownloadDirectory(const RsGxsGroupId &groupId, const std::string& directory)=0;
virtual bool getChannelDownloadDirectory(const RsGxsGroupId &groupId, std::string& directory)=0;
//virtual void setChannelAutoDownload(uint32_t& token, const RsGxsGroupId& groupId, bool autoDownload) = 0;
//virtual bool setMessageStatus(const std::string &msgId, const uint32_t status, const uint32_t statusMask);
//virtual bool setGroupSubscribeFlags(const std::string &groupId, uint32_t subscribeFlags, uint32_t subscribeMask);
//virtual bool groupRestoreKeys(const std::string &groupId);
virtual bool groupShareKeys(const RsGxsGroupId &groupId, std::set<RsPeerId>& peers)=0;
virtual bool groupShareKeys(const RsGxsGroupId &groupId, std::set<RsPeerId>& peers)=0;
// Overloaded subscribe fn.
virtual bool subscribeToGroup(uint32_t &token, const RsGxsGroupId &groupId, bool subscribe) = 0;
virtual bool subscribeToGroup(uint32_t &token, const RsGxsGroupId &groupId, bool subscribe) = 0;
virtual bool createGroup(uint32_t &token, RsGxsChannelGroup &group) = 0;
virtual bool createPost(uint32_t &token, RsGxsChannelPost &post) = 0;
virtual bool updateGroup(uint32_t &token, RsGxsChannelGroup &group) = 0;
// File Interface
virtual bool ExtraFileHash(const std::string &path, std::string filename) = 0;
virtual bool ExtraFileRemove(const RsFileHash &hash) = 0;
virtual bool createGroup(uint32_t &token, RsGxsChannelGroup &group) = 0;
virtual bool createPost(uint32_t &token, RsGxsChannelPost &post) = 0;
virtual bool updateGroup(uint32_t &token, RsGxsChannelGroup &group) = 0;
// File Interface
virtual bool ExtraFileHash(const std::string &path, std::string filename) = 0;
virtual bool ExtraFileRemove(const RsFileHash &hash) = 0;
};

View File

@ -0,0 +1,92 @@
/*
* RetroShare C++ Interface.
*
* Copyright 2018 by Cyril Soler
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License Version 2 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*
* Please report all bugs and problems to "retroshare@lunamutt.com".
*
*/
#pragma once
#include "retroshare/rsfiles.h"
#include "retroshare/rsturtle.h"
typedef RsPeerId RsGxsNetTunnelVirtualPeerId ;
struct RsGxsNetTunnelVirtualPeerInfo
{
enum { RS_GXS_NET_TUNNEL_VP_STATUS_UNKNOWN = 0x00, // unknown status.
RS_GXS_NET_TUNNEL_VP_STATUS_TUNNEL_OK = 0x01, // tunnel has been established and we're waiting for virtual peer id
RS_GXS_NET_TUNNEL_VP_STATUS_ACTIVE = 0x02 // virtual peer id is known. Data can transfer.
};
RsGxsNetTunnelVirtualPeerInfo() : vpid_status(RS_GXS_NET_TUNNEL_VP_STATUS_UNKNOWN), last_contact(0),side(0) { memset(encryption_master_key,0,32) ; }
virtual ~RsGxsNetTunnelVirtualPeerInfo(){}
uint8_t vpid_status ; // status of the peer
time_t last_contact ; // last time some data was sent/recvd
uint8_t side ; // client/server
uint8_t encryption_master_key[32];
TurtleVirtualPeerId turtle_virtual_peer_id ; // turtle peer to use when sending data to this vpid.
RsGxsGroupId group_id ; // group that virtual peer is providing
uint16_t service_id ; // this is used for checkng consistency of the incoming data
};
struct RsGxsNetTunnelGroupInfo
{
enum GroupStatus {
RS_GXS_NET_TUNNEL_GRP_STATUS_UNKNOWN = 0x00, // unknown status
RS_GXS_NET_TUNNEL_GRP_STATUS_IDLE = 0x01, // no virtual peers requested, just waiting
RS_GXS_NET_TUNNEL_GRP_STATUS_VPIDS_AVAILABLE = 0x02 // some virtual peers are available. Data can be read/written
};
enum GroupPolicy {
RS_GXS_NET_TUNNEL_GRP_POLICY_UNKNOWN = 0x00, // nothing has been set
RS_GXS_NET_TUNNEL_GRP_POLICY_PASSIVE = 0x01, // group is available for server side tunnels, but does not explicitely request tunnels
RS_GXS_NET_TUNNEL_GRP_POLICY_ACTIVE = 0x02, // group will only explicitely request tunnels if none available
RS_GXS_NET_TUNNEL_GRP_POLICY_REQUESTING = 0x03, // group explicitely requests tunnels
};
RsGxsNetTunnelGroupInfo() : group_policy(RS_GXS_NET_TUNNEL_GRP_POLICY_PASSIVE),group_status(RS_GXS_NET_TUNNEL_GRP_STATUS_IDLE),last_contact(0) {}
GroupPolicy group_policy ;
GroupStatus group_status ;
time_t last_contact ;
RsFileHash hash ;
uint16_t service_id ;
std::set<TurtleVirtualPeerId> virtual_peers ; // list of which virtual peers provide this group. Can me more than 1.
};
// This class is here to provide statistics about GXS dist sync internals. It
//
class RsGxsDistSync
{
public:
virtual void getStatistics(
std::map<RsGxsGroupId,RsGxsNetTunnelGroupInfo>& groups, // groups on the client and server side
std::map<RsGxsNetTunnelVirtualPeerId, RsGxsNetTunnelVirtualPeerInfo>& virtual_peers, // current virtual peers, which group they provide, and how to talk to them through turtle
std::map<TurtleVirtualPeerId,RsGxsNetTunnelVirtualPeerId>& turtle_vpid_to_net_tunnel_vpid,
Bias20Bytes& bias
) const =0;
};
extern RsGxsDistSync *rsGxsDistSync ;

View File

@ -32,6 +32,30 @@
#include "gxs/rsgxsdata.h"
#include "retroshare/rsgxsifacetypes.h"
/*!
* \brief The RsGxsGroupSymmary struct
* This structure is used to transport group summary information when a GXS service is searched. It contains the group information
* as well as a context string to tell where the information was found. It is more compact than a GroupMeta object, so as to make
* search responses as light as possible.
*/
struct RsGxsGroupSummary
{
RsGxsGroupSummary() : publish_ts(0), number_of_messages(0),last_message_ts(0),sign_flags(0),popularity(0) {}
RsGxsGroupId group_id ;
std::string group_name ;
std::string group_description ;
std::string search_context ;
RsGxsId author_id ;
time_t publish_ts ;
uint32_t number_of_messages ;
time_t last_message_ts ;
uint32_t sign_flags ;
uint32_t popularity ;
};
/*!
* Stores ids of changed gxs groups and messages. It is used to notify the GUI about changes.
*/
@ -44,6 +68,7 @@ public:
std::map<RsGxsGroupId, std::set<RsGxsMessageId> > mMsgsMeta;
std::list<RsGxsGroupId> mGrps;
std::list<RsGxsGroupId> mGrpsMeta;
std::list<TurtleRequestId> mDistantSearchReqs;
};
/*!

View File

@ -69,18 +69,18 @@ struct RsGroupMetaData : RsSerializable
RsGxsGroupId mGroupId;
std::string mGroupName;
uint32_t mGroupFlags; // Combination of FLAG_PRIVACY_PRIVATE | FLAG_PRIVACY_RESTRICTED | FLAG_PRIVACY_PUBLIC
uint32_t mSignFlags; // Combination of RSGXS_GROUP_SIGN_PUBLISH_MASK & RSGXS_GROUP_SIGN_AUTHOR_MASK.
uint32_t mGroupFlags; // Combination of FLAG_PRIVACY_PRIVATE | FLAG_PRIVACY_RESTRICTED | FLAG_PRIVACY_PUBLIC: diffusion
uint32_t mSignFlags; // Combination of RSGXS_GROUP_SIGN_PUBLISH_MASK & RSGXS_GROUP_SIGN_AUTHOR_MASK, i.e. what signatures are required for parent and child msgs
time_t mPublishTs; // Mandatory.
RsGxsId mAuthorId; // Optional.
RsGxsId mAuthorId; // Author of the group. Left to "000....0" if anonymous
// for circles
RsGxsCircleId mCircleId;
uint32_t mCircleType;
RsGxsCircleId mCircleId; // Id of the circle to which the group is restricted
uint32_t mCircleType; // combination of CIRCLE_TYPE_{ PUBLIC,EXTERNAL,YOUR_FRIENDS_ONLY,LOCAL,EXT_SELF,YOUR_EYES_ONLY }
// other stuff.
uint32_t mAuthenFlags;
uint32_t mAuthenFlags; // Actually not used yet.
RsGxsGroupId mParentGrpId;
// BELOW HERE IS LOCAL DATA, THAT IS NOT FROM MSG.

View File

@ -6,6 +6,7 @@
#include "retroshare/rstokenservice.h"
struct RsMsgMetaData ;
typedef uint32_t TurtleRequestId;
typedef std::map<RsGxsGroupId, std::vector<RsMsgMetaData> > GxsMsgMetaMap;
typedef std::map<RsGxsGrpMsgIdPair, std::vector<RsMsgMetaData> > GxsMsgRelatedMetaMap;
@ -18,7 +19,7 @@ typedef std::map<RsGxsGrpMsgIdPair, std::vector<RsMsgMetaData> > GxsMsgRelatedMe
struct RsGxsNotify
{
enum NotifyType
{ TYPE_PUBLISH, TYPE_RECEIVE, TYPE_PROCESSED, TYPE_PUBLISHKEY };
{ TYPE_PUBLISHED, TYPE_RECEIVED_NEW, TYPE_PROCESSED, TYPE_RECEIVED_PUBLISHKEY, TYPE_RECEIVED_DISTANT_SEARCH_RESULTS };
virtual ~RsGxsNotify() {}
virtual NotifyType getType() = 0;
@ -39,6 +40,17 @@ private:
bool mMetaChange;
};
class RsGxsDistantSearchResultChange: public RsGxsNotify
{
public:
RsGxsDistantSearchResultChange(TurtleRequestId id,const RsGxsGroupId& group_id) : mRequestId(id),mGroupId(group_id){}
NotifyType getType() { return TYPE_RECEIVED_DISTANT_SEARCH_RESULTS ; }
TurtleRequestId mRequestId ;
RsGxsGroupId mGroupId;
};
/*!
* Relevant to message changes
*/

View File

@ -238,12 +238,14 @@ static const uint32_t RS_GENERIC_ID_GXS_TUNNEL_ID_TYPE = 0x0010 ;
static const uint32_t RS_GENERIC_ID_GXS_DISTANT_CHAT_ID_TYPE = 0x0011 ;
static const uint32_t RS_GENERIC_ID_NODE_GROUP_ID_TYPE = 0x0012 ;
static const uint32_t RS_GENERIC_ID_SHA256_ID_TYPE = 0x0013 ;
static const uint32_t RS_GENERIC_ID_20_BYTES_UNTYPED = 0x0014 ;
typedef t_RsGenericIdType< SSL_ID_SIZE , false, RS_GENERIC_ID_SSL_ID_TYPE> SSLIdType ;
typedef t_RsGenericIdType< PGP_KEY_ID_SIZE , true, RS_GENERIC_ID_PGP_ID_TYPE> PGPIdType ;
typedef t_RsGenericIdType< SHA1_SIZE , false, RS_GENERIC_ID_SHA1_ID_TYPE> Sha1CheckSum ;
typedef t_RsGenericIdType< SHA256_SIZE , false, RS_GENERIC_ID_SHA256_ID_TYPE> Sha256CheckSum ;
typedef t_RsGenericIdType< PGP_KEY_FINGERPRINT_SIZE, true, RS_GENERIC_ID_PGP_FINGERPRINT_TYPE> PGPFingerprintType ;
typedef t_RsGenericIdType< SHA1_SIZE , true, RS_GENERIC_ID_20_BYTES_UNTYPED> Bias20Bytes ;
typedef t_RsGenericIdType< CERT_SIGN_LEN , false, RS_GENERIC_ID_GXS_GROUP_ID_TYPE > GXSGroupId ;
typedef t_RsGenericIdType< CERT_SIGN_LEN , false, RS_GENERIC_ID_GXS_ID_TYPE > GXSId ;

View File

@ -228,6 +228,8 @@ class NotifyClient
virtual void notifyCustomState (const std::string& /* peer_id */, const std::string& /* status_string */) {}
virtual void notifyHashingInfo (uint32_t /* type */, const std::string& /* fileinfo */) {}
virtual void notifyTurtleSearchResult (uint32_t /* search_id */, const std::list<TurtleFileInfo>& /* files */) {}
#warning MISSING CODE HERE
// virtual void notifyTurtleSearchResult (uint32_t /* search_id */, const std::list<TurtleGxsInfo >& /* groups */) {}
virtual void notifyPeerHasNewAvatar (std::string /* peer_id */) {}
virtual void notifyOwnAvatarChanged () {}
virtual void notifyOwnStatusMessageChanged () {}

View File

@ -33,7 +33,9 @@
#include <list>
#include <vector>
#include "serialiser/rstlvbinary.h"
#include "retroshare/rstypes.h"
#include "retroshare/rsgxsifacetypes.h"
namespace RsRegularExpression { class LinearizedExpression ; }
class RsTurtleClientService ;
@ -42,6 +44,7 @@ class RsTurtle;
extern RsTurtle *rsTurtle ;
typedef uint32_t TurtleRequestId ;
typedef RsPeerId TurtleVirtualPeerId;
// This is the structure used to send back results of the turtle search
// to the notifyBase class, or send info to the GUI.
@ -52,6 +55,7 @@ struct TurtleFileInfo
std::string name ;
uint64_t size ;
};
struct TurtleTunnelRequestDisplayInfo
{
uint32_t request_id ; // Id of the request
@ -109,8 +113,7 @@ class RsTurtle
// the request id, which will be further used by the gui to store results
// as they come back.
//
virtual TurtleRequestId turtleSearch(const std::string& match_string) = 0 ;
virtual TurtleRequestId turtleSearch(const RsRegularExpression::LinearizedExpression& expr) = 0 ;
virtual TurtleRequestId turtleSearch(unsigned char *search_bin_data,uint32_t search_bin_data_len,RsTurtleClientService *client_service) =0;
// Initiates tunnel handling for the given file hash. tunnels. Launches
// an exception if an error occurs during the initialization process. The

View File

@ -6,6 +6,8 @@
*/
#include "serialiser/rstypeserializer.h"
#include "serialiser/rsbaseserial.h"
#include "rsgxsitems.h"
#include "gxs/rsgxsdata.h"
#include <iostream>
@ -70,4 +72,62 @@ std::ostream &operator<<(std::ostream &out, const RsMsgMetaData &meta)
return out;
}
template<> uint32_t RsTypeSerializer::serial_size(const TurtleGxsInfo& i)
{
uint32_t s = 0 ;
s += 2 ; // service_id
s += i.group_id.SIZE_IN_BYTES ;
s += GetTlvStringSize(i.name) ;
return s;
}
template<> bool RsTypeSerializer::deserialize(const uint8_t data[],uint32_t size,uint32_t& offset,TurtleGxsInfo& i)
{
uint32_t saved_offset = offset ;
bool ok = true ;
ok &= getRawUInt16(data, size, &offset, &i.service_id); // service_id
ok &= i.group_id.deserialise(data, size, offset); // group_id
ok &= GetTlvString(data, size, &offset, TLV_TYPE_STR_NAME, i.name); // group name
if(!ok)
offset = saved_offset ;
return ok;
}
template<> bool RsTypeSerializer::serialize(uint8_t data[],uint32_t size,uint32_t& offset,const TurtleGxsInfo& i)
{
uint32_t saved_offset = offset ;
bool ok = true ;
ok &= setRawUInt16(data, size, &offset, i.service_id); // service_id
ok &= i.group_id.serialise(data, size, offset); // group_id
ok &= SetTlvString(data, size, &offset, TLV_TYPE_STR_NAME, i.name); // group name
if(!ok)
offset = saved_offset ;
return ok;
}
template<> void RsTypeSerializer::print_data(const std::string& n, const TurtleGxsInfo& i)
{
std::cerr << " [GXS Info ] " << n << " group_id=" << i.group_id << " service=" << std::hex << i.service_id << std::dec << ", name=" << i.name << std::endl;
}
void RsTurtleGxsSearchResultGroupSummaryItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx)
{
RsTypeSerializer::serial_process(j,ctx,result,"result") ;
}
void RsTurtleGxsSearchResultGroupDataItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx)
{
RsTypeSerializer::TlvMemBlock_proxy prox(encrypted_nxs_group_data,encrypted_nxs_group_data_len) ;
RsTypeSerializer::serial_process(j,ctx,prox,"encrypted_nxs_data") ;
}
RS_TYPE_SERIALIZER_FROM_JSON_NOT_IMPLEMENTED_DEF(TurtleGxsInfo)
RS_TYPE_SERIALIZER_TO_JSON_NOT_IMPLEMENTED_DEF(TurtleGxsInfo)

View File

@ -57,6 +57,82 @@ public:
RsMsgMetaData meta;
};
// We should make these items templates or generic classes so that each GXS service will handle them on its own.
static const uint8_t RS_PKT_SUBTYPE_GXS_SUBSTRING_SEARCH_ITEM = 0x20 ;
static const uint8_t RS_PKT_SUBTYPE_GXS_GROUP_SEARCH_ITEM = 0x21 ;
static const uint8_t RS_PKT_SUBTYPE_GXS_GROUP_SUMMARY_ITEM = 0x22 ;
static const uint8_t RS_PKT_SUBTYPE_GXS_GROUP_DATA_ITEM = 0x23 ;
class RsGxsTurtleSubStringSearchItem: public RsItem
{
public:
RsGxsTurtleSubStringSearchItem(uint16_t service): RsItem(RS_PKT_VERSION_SERVICE,service,RS_PKT_SUBTYPE_GXS_SUBSTRING_SEARCH_ITEM) {}
virtual ~RsGxsTurtleSubStringSearchItem() {}
std::string match_string ; // string to match
std::string GetKeywords() { return match_string; }
void clear() { match_string.clear() ; }
protected:
void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx);
};
class RsGxsTurtleGroupSearchItem: public RsItem
{
public:
RsGxsTurtleGroupSearchItem(uint16_t service): RsItem(RS_PKT_VERSION_SERVICE,service,RS_PKT_SUBTYPE_GXS_GROUP_SEARCH_ITEM) {}
virtual ~RsGxsTurtleGroupSearchItem() {}
uint16_t service_id ; // searvice to search
Sha1CheckSum hashed_group_id ; // the group ID is hashed in order to keep it private.
std::string GetKeywords() { return std::string("Group request for [hashed] ")+hashed_group_id.toStdString() ; }
void clear() { hashed_group_id.clear() ; }
protected:
void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx);
};
struct TurtleGxsInfo
{
uint16_t service_id ;
RsGxsGroupId group_id ;
RsGxsId author;
std::string name ;
std::string description ;
time_t last_post ;
uint32_t number_of_posts ;
};
class RsTurtleGxsSearchResultGroupSummaryItem: public RsItem
{
public:
RsTurtleGxsSearchResultGroupSummaryItem(uint16_t service) : RsItem(RS_PKT_VERSION_SERVICE,service,RS_PKT_SUBTYPE_GXS_GROUP_SUMMARY_ITEM){}
virtual ~RsTurtleGxsSearchResultGroupSummaryItem() {}
std::list<TurtleGxsInfo> result ;
void clear() { result.clear() ; }
protected:
void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx);
};
class RsTurtleGxsSearchResultGroupDataItem: public RsItem
{
public:
RsTurtleGxsSearchResultGroupDataItem(uint16_t service) : RsItem(RS_PKT_VERSION_SERVICE,service,RS_PKT_SUBTYPE_GXS_GROUP_DATA_ITEM){}
virtual ~RsTurtleGxsSearchResultGroupDataItem() {}
unsigned char *encrypted_nxs_group_data; // data is encrypted with group ID. Only the requester, or anyone who already know the group id can decrypt.
uint32_t encrypted_nxs_group_data_len ;
void clear() { free(encrypted_nxs_group_data); encrypted_nxs_group_data=NULL; encrypted_nxs_group_data_len=0; }
protected:
void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx);
};

View File

@ -97,6 +97,31 @@ void RsGxsMsgUpdateItem::serial_process(RsGenericSerializer::SerializeJob j,RsGe
RsTypeSerializer::serial_process(j,ctx,msgUpdateInfos,"msgUpdateInfos");
}
template<> bool RsTypeSerializer::serialize(uint8_t data[], uint32_t size, uint32_t &offset, const RsGxsMsgUpdateItem::MsgUpdateInfo& info)
{
bool ok = true ;
ok = ok && setRawUInt32(data,size,&offset,info.time_stamp);
ok = ok && setRawUInt32(data,size,&offset,info.message_count);
return ok;
}
template<> bool RsTypeSerializer::deserialize(const uint8_t data[], uint32_t size, uint32_t &offset, RsGxsMsgUpdateItem::MsgUpdateInfo& info)
{
bool ok = true ;
ok = ok && getRawUInt32(data,size,&offset,&info.time_stamp);
ok = ok && getRawUInt32(data,size,&offset,&info.message_count);
return ok;
}
template<> uint32_t RsTypeSerializer::serial_size(const RsGxsMsgUpdateItem::MsgUpdateInfo& /* info */) { return 8; }
template<> void RsTypeSerializer::print_data(const std::string& name,const RsGxsMsgUpdateItem::MsgUpdateInfo& info)
{
std::cerr << "[MsgUpdateInfo]: " << name << ": " << info.time_stamp << ", " << info.message_count << std::endl;
}
void RsGxsServerMsgUpdateItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx)
{
RsTypeSerializer::serial_process (j,ctx,grpId,"grpId");
@ -109,3 +134,4 @@ void RsGxsGrpConfigItem::serial_process(RsGenericSerializer::SerializeJob j,RsGe
RsTypeSerializer::serial_process<uint32_t>(j,ctx,msg_send_delay,"msg_send_delay") ;
RsTypeSerializer::serial_process<uint32_t>(j,ctx,msg_req_delay,"msg_req_delay") ;
}

View File

@ -30,6 +30,7 @@
#include "gxs/rsgxs.h"
#include "gxs/rsgxsdata.h"
#include "gxs/rsgxsnettunnel.h"
#include "serialiser/rstlvidset.h"
#include "serialiser/rstypeserializer.h"
#include "serialiser/rsserializable.h"
@ -41,6 +42,7 @@ const uint8_t RS_PKT_SUBTYPE_GXS_MSG_UPDATE = 0x03;
const uint8_t RS_PKT_SUBTYPE_GXS_SERVER_GRP_UPDATE = 0x04;
const uint8_t RS_PKT_SUBTYPE_GXS_SERVER_MSG_UPDATE = 0x08;
const uint8_t RS_PKT_SUBTYPE_GXS_GRP_CONFIG = 0x09;
const uint8_t RS_PKT_SUBTYPE_GXS_RANDOM_BIAS = 0x0a;
class RsGxsNetServiceItem: public RsItem
{
@ -188,7 +190,6 @@ public:
RsGxsGroupId grpId;
};
class RsGxsUpdateSerialiser : public RsServiceSerializer
{
public:

View File

@ -62,6 +62,7 @@
#include <fcntl.h>
#include "gxstunnel/p3gxstunnel.h"
#include "retroshare/rsgxsdistsync.h"
#include "file_sharing/p3filelists.h"
#define ENABLE_GROUTER
@ -1279,6 +1280,15 @@ int RsServer::StartupRetroShare()
RsNxsNetMgr* nxsMgr = new RsNxsNetMgrImpl(serviceCtrl);
/**** GXS Dist sync service ****/
#ifdef RS_USE_GXS_DISTANT_SYNC
RsGxsNetTunnelService *mGxsNetTunnel = new RsGxsNetTunnelService ;
rsGxsDistSync = mGxsNetTunnel ;
#else
RsGxsNetTunnelService *mGxsNetTunnel = NULL ;
#endif
/**** Identity service ****/
RsGeneralDataService* gxsid_ds = new RsDataService(currGxsDir + "/", "gxsid_db",
@ -1300,9 +1310,10 @@ int RsServer::StartupRetroShare()
RS_SERVICE_GXS_TYPE_GXSID, gxsid_ds, nxsMgr,
mGxsIdService, mGxsIdService->getServiceInfo(),
mReputations, mGxsCircles,mGxsIdService,
pgpAuxUtils,
false,false); // don't synchronise group automatic (need explicit group request)
pgpAuxUtils,mGxsNetTunnel,
false,false,true); // don't synchronise group automatic (need explicit group request)
// don't sync messages at all.
// allow distsync, so that we can grab GXS id requests for other services
// Normally we wouldn't need this (we do in other service):
// mGxsIdService->setNetworkExchangeService(gxsid_ns) ;
@ -1319,9 +1330,7 @@ int RsServer::StartupRetroShare()
RS_SERVICE_GXS_TYPE_GXSCIRCLE, gxscircles_ds, nxsMgr,
mGxsCircles, mGxsCircles->getServiceInfo(),
mReputations, mGxsCircles,mGxsIdService,
pgpAuxUtils,
true, // synchronise group automatic
true); // sync messages automatic, since they contain subscription requests.
pgpAuxUtils);
mGxsCircles->setNetworkExchangeService(gxscircles_ns) ;
@ -1373,7 +1382,7 @@ int RsServer::StartupRetroShare()
RS_SERVICE_GXS_TYPE_FORUMS, gxsforums_ds, nxsMgr,
mGxsForums, mGxsForums->getServiceInfo(),
mReputations, mGxsCircles,mGxsIdService,
pgpAuxUtils);
pgpAuxUtils);//,mGxsNetTunnel,true,true,true);
mGxsForums->setNetworkExchangeService(gxsforums_ns) ;
@ -1386,10 +1395,10 @@ int RsServer::StartupRetroShare()
// create GXS photo service
RsGxsNetService* gxschannels_ns = new RsGxsNetService(
RS_SERVICE_GXS_TYPE_CHANNELS, gxschannels_ds, nxsMgr,
mGxsChannels, mGxsChannels->getServiceInfo(),
mReputations, mGxsCircles,mGxsIdService,
pgpAuxUtils);
RS_SERVICE_GXS_TYPE_CHANNELS, gxschannels_ds, nxsMgr,
mGxsChannels, mGxsChannels->getServiceInfo(),
mReputations, mGxsCircles,mGxsIdService,
pgpAuxUtils,mGxsNetTunnel,true,true,true);
mGxsChannels->setNetworkExchangeService(gxschannels_ns) ;
@ -1444,7 +1453,7 @@ int RsServer::StartupRetroShare()
RsGxsNetService* gxstrans_ns = new RsGxsNetService(
RS_SERVICE_TYPE_GXS_TRANS, gxstrans_ds, nxsMgr, mGxsTrans,
mGxsTrans->getServiceInfo(), mReputations, mGxsCircles,
mGxsIdService, pgpAuxUtils,true,true,p3GxsTrans::GXS_STORAGE_PERIOD,p3GxsTrans::GXS_SYNC_PERIOD);
mGxsIdService, pgpAuxUtils,NULL,true,true,false,p3GxsTrans::GXS_STORAGE_PERIOD,p3GxsTrans::GXS_SYNC_PERIOD);
mGxsTrans->setNetworkExchangeService(gxstrans_ns);
pqih->addService(gxstrans_ns, true);
@ -1477,9 +1486,11 @@ int RsServer::StartupRetroShare()
pqih -> addService(fdb,true);
pqih -> addService(ftserver,true);
mGxsTunnels = new p3GxsTunnelService(mGxsIdService) ;
mGxsTunnels->connectToTurtleRouter(tr) ;
rsGxsTunnel = mGxsTunnels;
mGxsTunnels = new p3GxsTunnelService(mGxsIdService) ;
mGxsTunnels->connectToTurtleRouter(tr) ;
rsGxsTunnel = mGxsTunnels;
mGxsNetTunnel->connectToTurtleRouter(tr) ;
rsDisc = mDisc;
rsMsgs = new p3Msgs(msgSrv, chatSrv);
@ -1612,48 +1623,51 @@ int RsServer::StartupRetroShare()
serviceCtrl->registerServiceMonitor(mBwCtrl, mBwCtrl->getServiceInfo().mServiceType);
/**************************************************************************/
// Turtle search for GXS services
mGxsNetTunnel->registerSearchableService(gxschannels_ns) ;
/**************************************************************************/
//mConfigMgr->addConfiguration("ftserver.cfg", ftserver);
//
mConfigMgr->addConfiguration("gpg_prefs.cfg", AuthGPG::getAuthGPG());
mConfigMgr->loadConfiguration();
mConfigMgr->addConfiguration("peers.cfg", mPeerMgr);
mConfigMgr->addConfiguration("general.cfg", mGeneralConfig);
mConfigMgr->addConfiguration("msgs.cfg", msgSrv);
mConfigMgr->addConfiguration("chat.cfg", chatSrv);
mConfigMgr->addConfiguration("p3History.cfg", mHistoryMgr);
mConfigMgr->addConfiguration("p3Status.cfg", mStatusSrv);
mConfigMgr->addConfiguration("turtle.cfg", tr);
mConfigMgr->addConfiguration("gpg_prefs.cfg" , AuthGPG::getAuthGPG());
mConfigMgr->addConfiguration("gxsnettunnel.cfg", mGxsNetTunnel);
mConfigMgr->addConfiguration("peers.cfg" , mPeerMgr);
mConfigMgr->addConfiguration("general.cfg" , mGeneralConfig);
mConfigMgr->addConfiguration("msgs.cfg" , msgSrv);
mConfigMgr->addConfiguration("chat.cfg" , chatSrv);
mConfigMgr->addConfiguration("p3History.cfg" , mHistoryMgr);
mConfigMgr->addConfiguration("p3Status.cfg" , mStatusSrv);
mConfigMgr->addConfiguration("turtle.cfg" , tr);
#ifndef RETROTOR
mConfigMgr->addConfiguration("banlist.cfg", mBanList);
mConfigMgr->addConfiguration("banlist.cfg" , mBanList);
#endif
mConfigMgr->addConfiguration("servicecontrol.cfg", serviceCtrl);
mConfigMgr->addConfiguration("reputations.cfg", mReputations);
mConfigMgr->addConfiguration("reputations.cfg" , mReputations);
#ifdef ENABLE_GROUTER
mConfigMgr->addConfiguration("grouter.cfg", gr);
mConfigMgr->addConfiguration("grouter.cfg" , gr);
#endif
#ifdef RS_USE_BITDHT
mConfigMgr->addConfiguration("bitdht.cfg", mBitDht);
mConfigMgr->addConfiguration("bitdht.cfg" , mBitDht);
#endif
#ifdef RS_ENABLE_GXS
# ifdef RS_GXS_TRANS
mConfigMgr->addConfiguration("gxs_trans_ns.cfg", gxstrans_ns);
mConfigMgr->addConfiguration("gxs_trans.cfg", mGxsTrans);
mConfigMgr->addConfiguration("gxs_trans.cfg" , mGxsTrans);
# endif // RS_GXS_TRANS
mConfigMgr->addConfiguration("p3identity.cfg", mGxsIdService);
mConfigMgr->addConfiguration("identity.cfg", gxsid_ns);
mConfigMgr->addConfiguration("gxsforums.cfg", gxsforums_ns);
mConfigMgr->addConfiguration("p3identity.cfg" , mGxsIdService);
mConfigMgr->addConfiguration("identity.cfg" , gxsid_ns);
mConfigMgr->addConfiguration("gxsforums.cfg" , gxsforums_ns);
mConfigMgr->addConfiguration("gxsforums_srv.cfg", mGxsForums);
mConfigMgr->addConfiguration("gxschannels.cfg", gxschannels_ns);
mConfigMgr->addConfiguration("gxschannels.cfg" , gxschannels_ns);
mConfigMgr->addConfiguration("gxschannels_srv.cfg", mGxsChannels);
mConfigMgr->addConfiguration("gxscircles.cfg", gxscircles_ns);
mConfigMgr->addConfiguration("posted.cfg", posted_ns);
mConfigMgr->addConfiguration("gxscircles.cfg" , gxscircles_ns);
mConfigMgr->addConfiguration("posted.cfg" , posted_ns);
#ifdef RS_USE_WIKI
mConfigMgr->addConfiguration("wiki.cfg", wiki_ns);
#endif
@ -1824,6 +1838,8 @@ int RsServer::StartupRetroShare()
//rsWire = mWire;
/*** start up GXS core runner ***/
startServiceThread(mGxsNetTunnel, "gxs net tunnel");
startServiceThread(mGxsIdService, "gxs id");
startServiceThread(mGxsCircles, "gxs circle");
startServiceThread(mPosted, "gxs posted");

View File

@ -236,7 +236,7 @@ void p3GxsChannels::notifyChanges(std::vector<RsGxsNotify *> &changes)
RsGxsMsgChange *msgChange = dynamic_cast<RsGxsMsgChange *>(*it);
if (msgChange)
{
if (msgChange->getType() == RsGxsNotify::TYPE_RECEIVE)
if (msgChange->getType() == RsGxsNotify::TYPE_RECEIVED_NEW)
{
/* message received */
if (notify)
@ -289,11 +289,12 @@ void p3GxsChannels::notifyChanges(std::vector<RsGxsNotify *> &changes)
{
switch (grpChange->getType())
{
default:
case RsGxsNotify::TYPE_PROCESSED:
case RsGxsNotify::TYPE_PUBLISH:
case RsGxsNotify::TYPE_PUBLISHED:
break;
case RsGxsNotify::TYPE_RECEIVE:
case RsGxsNotify::TYPE_RECEIVED_NEW:
{
/* group received */
std::list<RsGxsGroupId> &grpList = grpChange->mGrpIdList;
@ -311,7 +312,7 @@ void p3GxsChannels::notifyChanges(std::vector<RsGxsNotify *> &changes)
break;
}
case RsGxsNotify::TYPE_PUBLISHKEY:
case RsGxsNotify::TYPE_RECEIVED_PUBLISHKEY:
{
/* group received */
std::list<RsGxsGroupId> &grpList = grpChange->mGrpIdList;
@ -1686,3 +1687,57 @@ void p3GxsChannels::handle_event(uint32_t event_type, const std::string &elabel)
}
}
TurtleRequestId p3GxsChannels::turtleGroupRequest(const RsGxsGroupId& group_id)
{
return netService()->turtleGroupRequest(group_id) ;
}
TurtleRequestId p3GxsChannels::turtleSearchRequest(const std::string& match_string)
{
return netService()->turtleSearchRequest(match_string) ;
}
bool p3GxsChannels::clearDistantSearchResults(TurtleRequestId req)
{
return netService()->clearDistantSearchResults(req);
}
bool p3GxsChannels::retrieveDistantSearchResults(TurtleRequestId req,std::map<RsGxsGroupId,RsGxsGroupSummary>& results)
{
return netService()->retrieveDistantSearchResults(req,results);
}
bool p3GxsChannels::retrieveDistantGroup(const RsGxsGroupId& group_id,RsGxsChannelGroup& distant_group)
{
RsGxsGroupSummary gs ;
if(netService()->retrieveDistantGroupSummary(group_id,gs))
{
// This is a placeholder information by the time we receive the full group meta data.
distant_group.mDescription = gs.group_description;
distant_group.mMeta.mGroupId = gs.group_id ;
distant_group.mMeta.mGroupName = gs.group_name;
distant_group.mMeta.mGroupFlags = GXS_SERV::FLAG_PRIVACY_PUBLIC ;
distant_group.mMeta.mSignFlags = gs.sign_flags;
distant_group.mMeta.mPublishTs = gs.publish_ts;
distant_group.mMeta.mAuthorId = gs.author_id;
distant_group.mMeta.mCircleType = GXS_CIRCLE_TYPE_PUBLIC ;// guessed, otherwise the group would not be search-able.
// other stuff.
distant_group.mMeta.mAuthenFlags = 0; // wild guess...
distant_group.mMeta.mSubscribeFlags = GXS_SERV::GROUP_SUBSCRIBE_NOT_SUBSCRIBED ;
distant_group.mMeta.mPop = gs.popularity; // Popularity = number of friend subscribers
distant_group.mMeta.mVisibleMsgCount = gs.number_of_messages; // Max messages reported by friends
distant_group.mMeta.mLastPost = gs.last_message_ts; // Timestamp for last message. Not used yet.
return true ;
}
else
return false ;
}

View File

@ -72,6 +72,12 @@ virtual void service_tick();
virtual bool saveList(bool &cleanup, std::list<RsItem *>&saveList); // @see p3Config::saveList(bool &cleanup, std::list<RsItem *>&)
virtual bool loadList(std::list<RsItem *>& loadList); // @see p3Config::loadList(std::list<RsItem *>&)
virtual TurtleRequestId turtleGroupRequest(const RsGxsGroupId& group_id);
virtual TurtleRequestId turtleSearchRequest(const std::string& match_string);
virtual bool retrieveDistantSearchResults(TurtleRequestId req, std::map<RsGxsGroupId, RsGxsGroupSummary> &results) ;
virtual bool clearDistantSearchResults(TurtleRequestId req);
virtual bool retrieveDistantGroup(const RsGxsGroupId& group_id,RsGxsChannelGroup& distant_group);
// Overloaded to cache new groups.
virtual RsGenExchange::ServiceCreate_Return service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySet& keySet);

View File

@ -218,7 +218,8 @@ void p3GxsCircles::notifyChanges(std::vector<RsGxsNotify *> &changes)
std::cerr << " Msgs for Group: " << mit->first << std::endl;
#endif
force_cache_reload(RsGxsCircleId(mit->first));
if (notify && (c->getType() == RsGxsNotify::TYPE_RECEIVE) )
if (notify && (c->getType() == RsGxsNotify::TYPE_RECEIVED_NEW) )
for (auto msgIdIt(mit->second.begin()), end(mit->second.end()); msgIdIt != end; ++msgIdIt)
{
const RsGxsMessageId& msgId = *msgIdIt;
@ -261,7 +262,7 @@ void p3GxsCircles::notifyChanges(std::vector<RsGxsNotify *> &changes)
std::cerr << " forcing cache loading for circle " << *git << " in order to trigger subscribe update." << std::endl;
#endif
force_cache_reload(RsGxsCircleId(*git)) ;
if (notify && (c->getType() == RsGxsNotify::TYPE_RECEIVE) )
if (notify && (c->getType() == RsGxsNotify::TYPE_RECEIVED_NEW) )
notify->AddFeedItem(RS_FEED_ITEM_CIRCLE_INVIT_REC,RsGxsCircleId(*git).toStdString(),"");
}

View File

@ -196,11 +196,12 @@ void p3GxsForums::notifyChanges(std::vector<RsGxsNotify *> &changes)
switch (c->getType())
{
default:
case RsGxsNotify::TYPE_PROCESSED:
case RsGxsNotify::TYPE_PUBLISH:
case RsGxsNotify::TYPE_PUBLISHED:
break;
case RsGxsNotify::TYPE_RECEIVE:
case RsGxsNotify::TYPE_RECEIVED_NEW:
{
RsGxsMsgChange *msgChange = dynamic_cast<RsGxsMsgChange*>(c);
if (msgChange)
@ -239,7 +240,7 @@ void p3GxsForums::notifyChanges(std::vector<RsGxsNotify *> &changes)
break;
}
case RsGxsNotify::TYPE_PUBLISHKEY:
case RsGxsNotify::TYPE_RECEIVED_PUBLISHKEY:
{
RsGxsGroupChange *grpChange = dynamic_cast<RsGxsGroupChange *>(*it);
if (grpChange)

View File

@ -278,7 +278,7 @@ void p3IdService::timeStampKey(const RsGxsId& gxs_id, const RsIdentityUsage& rea
return ;
}
#ifdef DEBUG_IDS
std::cerr << "(II) time stamping key " << gxs_id << " for the following reason: " << reason << std::endl;
std::cerr << "(II) time stamping key " << gxs_id << " for the following reason: " << reason.mUsageCode << std::endl;
#endif
RS_STACK_MUTEX(mIdMtx) ;
@ -2700,7 +2700,7 @@ void p3IdService::requestIdsFromNet()
bool request_can_proceed = false ;
for(cit2 = peers.begin(); cit2 != peers.end(); ++cit2)
if(rsPeers->isOnline(*cit2)) // make sure that the peer in online, so that we know that the request has some chance to succeed.
if(rsPeers->isOnline(*cit2) || mNes->isDistantPeer(*cit2)) // make sure that the peer in online, so that we know that the request has some chance to succeed.
{
requests[*cit2].push_back(cit->first);
request_can_proceed = true ;

View File

@ -122,7 +122,7 @@ void p3PostBase::notifyChanges(std::vector<RsGxsNotify *> &changes)
// It could be taken a step further and directly request these msgs for an update.
addGroupForProcessing(mit->first);
if (notify && msgChange->getType() == RsGxsNotify::TYPE_RECEIVE)
if (notify && msgChange->getType() == RsGxsNotify::TYPE_RECEIVED_NEW)
{
for (auto mit1 = mit->second.begin(); mit1 != mit->second.end(); ++mit1)
{
@ -149,7 +149,7 @@ void p3PostBase::notifyChanges(std::vector<RsGxsNotify *> &changes)
std::cerr << std::endl;
#endif
if (notify && groupChange->getType() == RsGxsNotify::TYPE_RECEIVE)
if (notify && groupChange->getType() == RsGxsNotify::TYPE_RECEIVED_NEW)
{
notify->AddFeedItem(RS_FEED_ITEM_POSTED_NEW, git->toStdString());
}

View File

@ -34,6 +34,7 @@
#endif
#include "rsserver/p3face.h"
#include "crypto/rscrypto.h"
#include "pqi/authssl.h"
#include "pqi/p3linkmgr.h"
@ -63,11 +64,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.
@ -79,17 +83,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 } ;
@ -151,13 +156,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";
@ -165,7 +172,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;
@ -184,7 +191,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;
@ -242,7 +249,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) ;
@ -370,8 +377,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 ;
@ -552,7 +559,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
@ -614,7 +621,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)) ;
@ -659,7 +666,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)) ;
}
}
@ -724,7 +731,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")
{
@ -824,7 +831,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.
@ -833,10 +840,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)) ;
@ -862,8 +871,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
@ -871,7 +878,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)
@ -882,27 +889,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.
@ -910,67 +947,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.
@ -1007,14 +994,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) ;
@ -1028,67 +1015,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) ;
}
}
// -----------------------------------------------------------------------------------//
@ -1150,8 +1264,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
@ -1189,7 +1303,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 ;
@ -1312,13 +1426,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 ;
}
@ -1456,7 +1570,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
@ -1559,7 +1673,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
@ -1590,7 +1704,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)
@ -1616,7 +1730,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
@ -1773,7 +1887,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;
@ -1796,7 +1912,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 ;
@ -1812,7 +1928,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;
@ -1835,7 +1951,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 ;
@ -1907,6 +2023,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)
{
{
@ -1947,29 +2091,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 ;
}
@ -1979,14 +2143,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) ;
}
@ -2068,7 +2227,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)
@ -2080,6 +2239,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,
@ -2114,12 +2295,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

@ -169,10 +169,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
{
@ -244,11 +246,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
@ -332,6 +339,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 -------------------------//
@ -385,10 +398,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);
@ -410,7 +422,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 ;
@ -425,7 +437,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

@ -28,10 +28,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 ;
@ -48,20 +50,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 ;
@ -143,12 +169,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

@ -16,20 +16,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 */
@ -46,49 +50,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() ; }
@ -96,10 +117,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
@ -110,15 +132,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 */
/***********************************************************************************/
@ -128,10 +226,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:
@ -167,24 +265,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

@ -42,51 +42,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 ;
};

View File

@ -165,8 +165,10 @@ SearchDialog::SearchDialog(QWidget *parent)
QHeaderView_setSectionResizeModeColumn(_smheader, SS_KEYWORDS_COL, QHeaderView::Interactive);
QHeaderView_setSectionResizeModeColumn(_smheader, SS_RESULTS_COL, QHeaderView::Interactive);
_smheader->resizeSection ( SS_KEYWORDS_COL, 160 );
_smheader->resizeSection ( SS_RESULTS_COL, 50 );
float f = QFontMetricsF(font()).height()/14.0 ;
_smheader->resizeSection ( SS_KEYWORDS_COL, 160*f );
_smheader->resizeSection ( SS_RESULTS_COL, 50*f );
ui.searchResultWidget->setColumnCount(SR_COL_COUNT);
_smheader = ui.searchResultWidget->header () ;
@ -174,12 +176,12 @@ SearchDialog::SearchDialog(QWidget *parent)
QHeaderView_setSectionResizeModeColumn(_smheader, SR_SIZE_COL, QHeaderView::Interactive);
QHeaderView_setSectionResizeModeColumn(_smheader, SR_SOURCES_COL, QHeaderView::Interactive);
_smheader->resizeSection ( SR_NAME_COL, 240 );
_smheader->resizeSection ( SR_SIZE_COL, 75 );
_smheader->resizeSection ( SR_SOURCES_COL, 75 );
_smheader->resizeSection ( SR_TYPE_COL, 75 );
_smheader->resizeSection ( SR_AGE_COL, 90 );
_smheader->resizeSection ( SR_HASH_COL, 240 );
_smheader->resizeSection ( SR_NAME_COL, 240*f );
_smheader->resizeSection ( SR_SIZE_COL, 75*f );
_smheader->resizeSection ( SR_SOURCES_COL, 75*f );
_smheader->resizeSection ( SR_TYPE_COL, 75*f );
_smheader->resizeSection ( SR_AGE_COL, 90*f );
_smheader->resizeSection ( SR_HASH_COL, 240*f );
// set header text aligment
QTreeWidgetItem * headerItem = ui.searchResultWidget->headerItem();
@ -201,10 +203,10 @@ SearchDialog::SearchDialog(QWidget *parent)
// load settings
processSettings(true);
ui._ownFiles_CB->setMinimumWidth(20);
ui._friendListsearch_SB->setMinimumWidth(20);
ui._anonF2Fsearch_CB->setMinimumWidth(20);
ui.label->setMinimumWidth(20);
ui._ownFiles_CB->setMinimumWidth(20*f);
ui._friendListsearch_SB->setMinimumWidth(20*f);
ui._anonF2Fsearch_CB->setMinimumWidth(20*f);
ui.label->setMinimumWidth(20*f);
// workaround for Qt bug, be solved in next Qt release 4.7.0
// https://bugreports.qt-project.org/browse/QTBUG-8270
@ -792,7 +794,7 @@ void SearchDialog::advancedSearch(RsRegularExpression::Expression* expression)
RsRegularExpression::LinearizedExpression e ;
expression->linearize(e) ;
TurtleRequestId req_id = rsTurtle->turtleSearch(e) ;
TurtleRequestId req_id = rsFiles->turtleSearch(e) ;
// This will act before turtle results come to the interface, thanks to the signals scheduling policy.
initSearchResult(QString::fromStdString(e.GetStrings()),req_id, ui.FileTypeComboBox->currentIndex(), true) ;
@ -858,9 +860,9 @@ void SearchDialog::searchKeywords(const QString& keywords)
if(ui._anonF2Fsearch_CB->isChecked())
{
if(n==1)
req_id = rsTurtle->turtleSearch(words.front()) ;
req_id = rsFiles->turtleSearch(words.front()) ;
else
req_id = rsTurtle->turtleSearch(lin_exp) ;
req_id = rsFiles->turtleSearch(lin_exp) ;
}
else
req_id = RSRandom::random_u32() ; // generate a random 32 bits request id

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>758</width>
<height>339</height>
<width>1531</width>
<height>889</height>
</rect>
</property>
<property name="sizePolicy">
@ -32,7 +32,16 @@
<enum>QFrame::Sunken</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="margin">
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>
@ -55,15 +64,24 @@
</size>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="horizontalSpacing">
<number>0</number>
</property>
<property name="verticalSpacing">
<number>1</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="LineEditClear" name="lineEdit">
<property name="toolTip">
@ -307,7 +325,7 @@
<string>Any</string>
</property>
<property name="icon">
<iconset resource="images.qrc">
<iconset resource="../images.qrc">
<normaloff>:/images/FileTypeAny.png</normaloff>:/images/FileTypeAny.png</iconset>
</property>
</item>
@ -316,7 +334,7 @@
<string>Archive</string>
</property>
<property name="icon">
<iconset resource="images.qrc">
<iconset resource="../images.qrc">
<normaloff>:/images/FileTypeArchive.png</normaloff>:/images/FileTypeArchive.png</iconset>
</property>
</item>
@ -325,7 +343,7 @@
<string>Audio</string>
</property>
<property name="icon">
<iconset resource="images.qrc">
<iconset resource="../images.qrc">
<normaloff>:/images/FileTypeAudio.png</normaloff>:/images/FileTypeAudio.png</iconset>
</property>
</item>
@ -334,7 +352,7 @@
<string>CD-Image</string>
</property>
<property name="icon">
<iconset resource="images.qrc">
<iconset resource="../images.qrc">
<normaloff>:/images/FileTypeCDImage.png</normaloff>:/images/FileTypeCDImage.png</iconset>
</property>
</item>
@ -343,7 +361,7 @@
<string>Document</string>
</property>
<property name="icon">
<iconset resource="images.qrc">
<iconset resource="../images.qrc">
<normaloff>:/images/FileTypeDocument.png</normaloff>:/images/FileTypeDocument.png</iconset>
</property>
</item>
@ -352,7 +370,7 @@
<string>Picture</string>
</property>
<property name="icon">
<iconset resource="images.qrc">
<iconset resource="../images.qrc">
<normaloff>:/images/FileTypePicture.png</normaloff>:/images/FileTypePicture.png</iconset>
</property>
</item>
@ -361,7 +379,7 @@
<string>Program</string>
</property>
<property name="icon">
<iconset resource="images.qrc">
<iconset resource="../images.qrc">
<normaloff>:/images/FileTypeProgram.png</normaloff>:/images/FileTypeProgram.png</iconset>
</property>
</item>
@ -370,7 +388,7 @@
<string>Video</string>
</property>
<property name="icon">
<iconset resource="images.qrc">
<iconset resource="../images.qrc">
<normaloff>:/images/FileTypeVideo.png</normaloff>:/images/FileTypeVideo.png</iconset>
</property>
</item>
@ -379,7 +397,7 @@
<string>Directory</string>
</property>
<property name="icon">
<iconset resource="images.qrc">
<iconset resource="../images.qrc">
<normaloff>:/images/folder16.png</normaloff>:/images/folder16.png</iconset>
</property>
</item>
@ -406,7 +424,7 @@
<string>Download selected</string>
</property>
<property name="icon">
<iconset resource="images.qrc">
<iconset resource="../images.qrc">
<normaloff>:/images/download16.png</normaloff>:/images/download16.png</iconset>
</property>
</widget>
@ -423,7 +441,7 @@
<customwidget>
<class>LineEditClear</class>
<extends>QLineEdit</extends>
<header>gui/common/LineEditClear.h</header>
<header location="global">gui/common/LineEditClear.h</header>
</customwidget>
<customwidget>
<class>SearchTreeWidget</class>
@ -432,7 +450,7 @@
</customwidget>
</customwidgets>
<resources>
<include location="images.qrc"/>
<include location="../images.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -1140,14 +1140,14 @@ void LocalSharedFilesDialog::spawnCustomPopupMenu( QPoint point )
{
shareChannelMenu.setIcon(QIcon(IMAGE_CHANNEL));
std::list<RsGroupMetaData> grp_metas ;
std::map<RsGxsGroupId,RsGroupMetaData> grp_metas ;
channelDialog->getGroupList(grp_metas) ;
std::vector<std::pair<std::string,RsGxsGroupId> > grplist ; // I dont use a std::map because two or more channels may have the same name.
for(auto it(grp_metas.begin());it!=grp_metas.end();++it)
if(IS_GROUP_PUBLISHER((*it).mSubscribeFlags) && IS_GROUP_SUBSCRIBED((*it).mSubscribeFlags))
grplist.push_back(std::make_pair((*it).mGroupName, (*it).mGroupId));
if(IS_GROUP_PUBLISHER((*it).second.mSubscribeFlags) && IS_GROUP_SUBSCRIBED((*it).second.mSubscribeFlags))
grplist.push_back(std::make_pair((*it).second.mGroupName, (*it).second.mGroupId));
std::sort(grplist.begin(),grplist.end(),ChannelCompare()) ;
@ -1164,14 +1164,14 @@ void LocalSharedFilesDialog::spawnCustomPopupMenu( QPoint point )
{
shareForumMenu.setIcon(QIcon(IMAGE_FORUMS));
std::list<RsGroupMetaData> grp_metas ;
std::map<RsGxsGroupId,RsGroupMetaData> grp_metas ;
forumsDialog->getGroupList(grp_metas) ;
std::vector<std::pair<std::string,RsGxsGroupId> > grplist ; // I dont use a std::map because two or more channels may have the same name.
for(auto it(grp_metas.begin());it!=grp_metas.end();++it)
if(IS_GROUP_SUBSCRIBED((*it).mSubscribeFlags))
grplist.push_back(std::make_pair((*it).mGroupName, (*it).mGroupId));
if(IS_GROUP_SUBSCRIBED((*it).second.mSubscribeFlags))
grplist.push_back(std::make_pair((*it).second.mGroupName, (*it).second.mGroupId));
std::sort(grplist.begin(),grplist.end(),ChannelCompare()) ;

View File

@ -454,6 +454,10 @@ void PostedListWidget::applyRanking()
ui->scrollAreaWidgetContents->update();
}
void PostedListWidget::blank()
{
clearPosts();
}
void PostedListWidget::clearPosts()
{
/* clear all messages */

View File

@ -63,6 +63,7 @@ protected:
virtual void insertAllPosts(const uint32_t &token, GxsMessageFramePostThread *thread);
virtual void insertPosts(const uint32_t &token);
virtual void clearPosts();
virtual void blank();
virtual bool navigatePostItem(const RsGxsMessageId& msgId);
/* GxsMessageFrameWidget */

View File

@ -18,6 +18,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
****************************************************************/
#include <iostream>
#include "GroupTreeWidget.h"
#include "ui_GroupTreeWidget.h"
@ -58,6 +60,8 @@
#define ROLE_SUBSCRIBE_FLAGS Qt::UserRole + 8
#define ROLE_COLOR Qt::UserRole + 9
#define ROLE_SAVED_ICON Qt::UserRole + 10
#define ROLE_SEARCH_STRING Qt::UserRole + 11
#define ROLE_REQUEST_ID Qt::UserRole + 12
#define FILTER_NAME_INDEX 0
#define FILTER_DESC_INDEX 1
@ -132,6 +136,10 @@ GroupTreeWidget::GroupTreeWidget(QWidget *parent) :
ui->filterLineEdit->addFilter(QIcon(), tr("Description"), FILTER_DESC_INDEX , tr("Search Description"));
ui->filterLineEdit->setCurrentFilter(FILTER_NAME_INDEX);
ui->distantSearchLineEdit->setPlaceholderText(tr("Search entire network...")) ;
connect(ui->distantSearchLineEdit,SIGNAL(returnPressed()),this,SLOT(distantSearch())) ;
/* Initialize display button */
initDisplayMenu(ui->displayButton);
@ -407,6 +415,54 @@ QTreeWidgetItem *GroupTreeWidget::addCategoryItem(const QString &name, const QIc
return item;
}
void GroupTreeWidget::removeSearchItem(QTreeWidgetItem *item)
{
ui->treeWidget->takeTopLevelItem(ui->treeWidget->indexOfTopLevelItem(item)) ;
}
QTreeWidgetItem *GroupTreeWidget::addSearchItem(const QString& search_string, uint32_t id, const QIcon& icon)
{
QTreeWidgetItem *item = addCategoryItem(search_string,icon,true);
item->setData(COLUMN_DATA,ROLE_SEARCH_STRING,search_string) ;
item->setData(COLUMN_DATA,ROLE_REQUEST_ID ,id) ;
return item;
}
void GroupTreeWidget::setDistSearchVisible(bool visible)
{
ui->distantSearchLineEdit->setVisible(visible);
}
bool GroupTreeWidget::isSearchRequestResult(QPoint &point,QString& group_id,uint32_t& search_req_id)
{
QTreeWidgetItem *item = ui->treeWidget->itemAt(point);
if (item == NULL)
return false;
QTreeWidgetItem *parent = item->parent();
if(parent == NULL)
return false ;
search_req_id = parent->data(COLUMN_DATA, ROLE_REQUEST_ID).toUInt();
group_id = itemId(item) ;
return search_req_id > 0;
}
bool GroupTreeWidget::isSearchRequestItem(QPoint &point,uint32_t& search_req_id)
{
QTreeWidgetItem *item = ui->treeWidget->itemAt(point);
if (item == NULL)
return false;
search_req_id = item->data(COLUMN_DATA, ROLE_REQUEST_ID).toUInt();
return search_req_id > 0;
}
QString GroupTreeWidget::itemId(QTreeWidgetItem *item)
{
if (item == NULL) {
@ -770,6 +826,13 @@ void GroupTreeWidget::resort(QTreeWidgetItem *categoryItem)
}
}
void GroupTreeWidget::distantSearch()
{
emit distantSearchRequested(ui->distantSearchLineEdit->text());
ui->distantSearchLineEdit->clear();
}
void GroupTreeWidget::sort()
{
resort(NULL);

View File

@ -82,6 +82,11 @@ public:
// Add a new category item
QTreeWidgetItem *addCategoryItem(const QString &name, const QIcon &icon, bool expand);
// Add a new search item
void setDistSearchVisible(bool) ; // shows/hides distant search UI parts.
QTreeWidgetItem *addSearchItem(const QString& search_string, uint32_t id, const QIcon &icon) ;
void removeSearchItem(QTreeWidgetItem *item);
// Get id of item
QString itemId(QTreeWidgetItem *item);
QString itemIdAt(QPoint &point);
@ -90,6 +95,9 @@ public:
// Set the unread count of an item
void setUnreadCount(QTreeWidgetItem *item, int unreadCount);
bool isSearchRequestItem(QPoint &point,uint32_t& search_req_id);
bool isSearchRequestResult(QPoint &point, QString &group_id, uint32_t& search_req_id);
QTreeWidgetItem *getItemFromId(const QString &id);
QTreeWidgetItem *activateId(const QString &id, bool focus);
@ -110,6 +118,7 @@ signals:
void treeCustomContextMenuRequested(const QPoint &pos);
void treeCurrentItemChanged(const QString &id);
void treeItemActivated(const QString &id);
void distantSearchRequested(const QString&) ;
protected:
void changeEvent(QEvent *e);
@ -119,6 +128,7 @@ private slots:
void currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous);
void itemActivated(QTreeWidgetItem *item, int column);
void filterChanged();
void distantSearch();
void sort();

View File

@ -124,6 +124,13 @@
</column>
</widget>
</item>
<item>
<widget class="QLineEdit" name="distantSearchLineEdit">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Searches a single keyword into the reachable network.&lt;/p&gt;&lt;p&gt;Objects already provided by friend nodes are not reported.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>

View File

@ -46,6 +46,8 @@
#define IMAGE_EDIT ":/images/edit_16.png"
#define IMAGE_SHARE ":/images/share-icon-16.png"
#define IMAGE_TABNEW ":/images/tab-new.png"
#define IMAGE_DELETE ":/images/delete.png"
#define IMAGE_RETRIEVE ":/images/edit_add24.png"
#define IMAGE_COMMENT ""
#define TOKEN_TYPE_GROUP_SUMMARY 1
@ -65,7 +67,7 @@
*/
/** Constructor */
GxsGroupFrameDialog::GxsGroupFrameDialog(RsGxsIfaceHelper *ifaceImpl, QWidget *parent)
GxsGroupFrameDialog::GxsGroupFrameDialog(RsGxsIfaceHelper *ifaceImpl, QWidget *parent,bool allow_dist_sync)
: RsGxsUpdateBroadcastPage(ifaceImpl, parent)
{
/* Invoke the Qt Designer generated object setup routine */
@ -73,6 +75,7 @@ GxsGroupFrameDialog::GxsGroupFrameDialog(RsGxsIfaceHelper *ifaceImpl, QWidget *p
ui->setupUi(this);
mInitialized = false;
mDistSyncAllowed = allow_dist_sync;
mInFill = false;
mCountChildMsgs = false;
mYourGroups = NULL;
@ -92,13 +95,18 @@ GxsGroupFrameDialog::GxsGroupFrameDialog(RsGxsIfaceHelper *ifaceImpl, QWidget *p
mStateHelper->addWidget(TOKEN_TYPE_GROUP_SUMMARY, ui->loadingLabel, UISTATE_LOADING_VISIBLE);
connect(ui->groupTreeWidget, SIGNAL(treeCustomContextMenuRequested(QPoint)), this, SLOT(groupTreeCustomPopupMenu(QPoint)));
connect(ui->groupTreeWidget, SIGNAL(treeCurrentItemChanged(QString)), this, SLOT(changedGroup(QString)));
connect(ui->groupTreeWidget, SIGNAL(treeCurrentItemChanged(QString)), this, SLOT(changedCurrentGroup(QString)));
connect(ui->groupTreeWidget->treeWidget(), SIGNAL(signalMouseMiddleButtonClicked(QTreeWidgetItem*)), this, SLOT(groupTreeMiddleButtonClicked(QTreeWidgetItem*)));
connect(ui->messageTabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(messageTabCloseRequested(int)));
connect(ui->messageTabWidget, SIGNAL(currentChanged(int)), this, SLOT(messageTabChanged(int)));
connect(ui->todoPushButton, SIGNAL(clicked()), this, SLOT(todo()));
ui->groupTreeWidget->setDistSearchVisible(allow_dist_sync) ;
if(allow_dist_sync)
connect(ui->groupTreeWidget, SIGNAL(distantSearchRequested(const QString&)), this, SLOT(searchNetwork(const QString&)));
/* Set initial size the splitter */
ui->splitter->setStretchFactor(0, 0);
ui->splitter->setStretchFactor(1, 1);
@ -121,7 +129,7 @@ GxsGroupFrameDialog::~GxsGroupFrameDialog()
delete(ui);
}
void GxsGroupFrameDialog::getGroupList(std::list<RsGroupMetaData>& group_list)
void GxsGroupFrameDialog::getGroupList(std::map<RsGxsGroupId, RsGroupMetaData> &group_list)
{
group_list = mCachedGroupMetas ;
@ -243,6 +251,55 @@ void GxsGroupFrameDialog::updateDisplay(bool complete)
updateMessageSummaryList(msgIt->first);
}
}
updateSearchResults() ;
}
void GxsGroupFrameDialog::updateSearchResults()
{
const std::set<TurtleRequestId>& reqs = getSearchResults();
for(auto it(reqs.begin());it!=reqs.end();++it)
{
std::cerr << "updating search ID " << std::hex << *it << std::dec << std::endl;
std::map<RsGxsGroupId,RsGxsGroupSummary> group_infos;
getDistantSearchResults(*it,group_infos) ;
std::cerr << "retrieved " << std::endl;
auto it2 = mSearchGroupsItems.find(*it);
if(mSearchGroupsItems.end() == it2)
{
std::cerr << "GxsGroupFrameDialog::updateSearchResults(): received result notification for req " << std::hex << *it << std::dec << " but no item present!" << std::endl;
continue ; // we could create the item just as well but since this situation is not supposed to happen, I prefer to make this a failure case.
}
QList<GroupItemInfo> group_items ;
for(auto it3(group_infos.begin());it3!=group_infos.end();++it3)
if(mCachedGroupMetas.find(it3->first) == mCachedGroupMetas.end())
{
std::cerr << " adding new group " << it3->first << " " << it3->second.group_id << " \"" << it3->second.group_name << "\"" << std::endl;
GroupItemInfo i ;
i.id = QString(it3->second.group_id.toStdString().c_str()) ;
i.name = QString::fromUtf8(it3->second.group_name.c_str()) ;
i.description = QString::fromUtf8(it3->second.group_description.c_str()) ;
i.popularity = 0; // could be set to the number of hits
i.lastpost = QDateTime::fromTime_t(it3->second.last_message_ts);
i.subscribeFlags = 0; // irrelevant here
i.publishKey = false ; // IS_GROUP_PUBLISHER(groupInfo.mSubscribeFlags) ;
i.adminKey = false ; // IS_GROUP_ADMIN(groupInfo.mSubscribeFlags) ;
i.max_visible_posts = it3->second.number_of_messages ;
group_items.push_back(i);
}
ui->groupTreeWidget->fillGroupItems(it2->second, group_items);
}
}
void GxsGroupFrameDialog::todo()
@ -250,98 +307,149 @@ void GxsGroupFrameDialog::todo()
QMessageBox::information(this, "Todo", text(TEXT_TODO));
}
void GxsGroupFrameDialog::removeCurrentSearch()
{
QAction *action = dynamic_cast<QAction*>(sender()) ;
if(!action)
return ;
TurtleRequestId search_request_id = action->data().toUInt();
auto it = mSearchGroupsItems.find(search_request_id) ;
if(it == mSearchGroupsItems.end())
return ;
ui->groupTreeWidget->removeSearchItem(it->second) ;
mSearchGroupsItems.erase(it);
mKnownGroups.erase(search_request_id);
}
void GxsGroupFrameDialog::removeAllSearches()
{
for(auto it(mSearchGroupsItems.begin());it!=mSearchGroupsItems.end();++it)
ui->groupTreeWidget->removeSearchItem(it->second) ;
mSearchGroupsItems.clear();
mKnownGroups.clear();
}
void GxsGroupFrameDialog::groupTreeCustomPopupMenu(QPoint point)
{
QMenu contextMnu(this);
// First separately handle the case of search top level items
TurtleRequestId search_request_id = 0 ;
if(ui->groupTreeWidget->isSearchRequestItem(point,search_request_id))
{
QMenu contextMnu(this);
contextMnu.addAction(QIcon(IMAGE_DELETE), tr("Remove this search"), this, SLOT(removeCurrentSearch()))->setData(search_request_id);
contextMnu.addAction(QIcon(IMAGE_DELETE), tr("Remove all searches"), this, SLOT(removeAllSearches()));
contextMnu.exec(QCursor::pos());
return ;
}
// Then check whether we have a searched item, or a normal group
QString group_id_s ;
if(ui->groupTreeWidget->isSearchRequestResult(point,group_id_s,search_request_id))
{
QMenu contextMnu(this);
contextMnu.addAction(QIcon(IMAGE_RETRIEVE), tr("Request data"), this, SLOT(distantRequestGroupData()))->setData(group_id_s);
contextMnu.exec(QCursor::pos());
return ;
}
QString id = ui->groupTreeWidget->itemIdAt(point);
if (!id.isEmpty())
{
if (id.isEmpty()) return;
mGroupId = RsGxsGroupId(id.toStdString());
int subscribeFlags = ui->groupTreeWidget->subscribeFlags(QString::fromStdString(mGroupId.toStdString()));
mGroupId = RsGxsGroupId(id.toStdString());
int subscribeFlags = ui->groupTreeWidget->subscribeFlags(QString::fromStdString(mGroupId.toStdString()));
bool isAdmin = IS_GROUP_ADMIN(subscribeFlags);
bool isPublisher = IS_GROUP_PUBLISHER(subscribeFlags);
bool isSubscribed = IS_GROUP_SUBSCRIBED(subscribeFlags);
bool isAdmin = IS_GROUP_ADMIN(subscribeFlags);
bool isPublisher = IS_GROUP_PUBLISHER(subscribeFlags);
bool isSubscribed = IS_GROUP_SUBSCRIBED(subscribeFlags);
QMenu contextMnu(this);
QAction *action;
QAction *action;
if (mMessageWidget) {
action = contextMnu.addAction(QIcon(IMAGE_TABNEW), tr("Open in new tab"), this, SLOT(openInNewTab()));
if (mGroupId.isNull() || messageWidget(mGroupId, true)) {
action->setEnabled(false);
}
if (mMessageWidget) {
action = contextMnu.addAction(QIcon(IMAGE_TABNEW), tr("Open in new tab"), this, SLOT(openInNewTab()));
if (mGroupId.isNull() || messageWidget(mGroupId, true)) {
action->setEnabled(false);
}
}
if (isSubscribed) {
action = contextMnu.addAction(QIcon(IMAGE_UNSUBSCRIBE), tr("Unsubscribe"), this, SLOT(unsubscribeGroup()));
action->setEnabled (!mGroupId.isNull() && IS_GROUP_SUBSCRIBED(subscribeFlags));
} else {
action = contextMnu.addAction(QIcon(IMAGE_SUBSCRIBE), tr("Subscribe"), this, SLOT(subscribeGroup()));
action->setDisabled (mGroupId.isNull() || IS_GROUP_SUBSCRIBED(subscribeFlags));
}
if (isSubscribed) {
action = contextMnu.addAction(QIcon(IMAGE_UNSUBSCRIBE), tr("Unsubscribe"), this, SLOT(unsubscribeGroup()));
action->setEnabled (!mGroupId.isNull() && IS_GROUP_SUBSCRIBED(subscribeFlags));
} else {
action = contextMnu.addAction(QIcon(IMAGE_SUBSCRIBE), tr("Subscribe"), this, SLOT(subscribeGroup()));
action->setDisabled (mGroupId.isNull() || IS_GROUP_SUBSCRIBED(subscribeFlags));
}
contextMnu.addSeparator();
contextMnu.addAction(QIcon(icon(ICON_NEW)), text(TEXT_NEW), this, SLOT(newGroup()));
action = contextMnu.addAction(QIcon(IMAGE_INFO), tr("Show Details"), this, SLOT(showGroupDetails()));
action->setEnabled (!mGroupId.isNull());
action = contextMnu.addAction(QIcon(IMAGE_EDIT), tr("Edit Details"), this, SLOT(editGroupDetails()));
action->setEnabled (!mGroupId.isNull() && isAdmin);
uint32_t current_store_time = mInterface->getStoragePeriod(mGroupId)/86400 ;
uint32_t current_sync_time = mInterface->getSyncPeriod(mGroupId)/86400 ;
std::cerr << "Got sync=" << current_sync_time << ". store=" << current_store_time << std::endl;
QAction *actnn = NULL;
QMenu *ctxMenu2 = contextMnu.addMenu(tr("Synchronise posts of last...")) ;
actnn = ctxMenu2->addAction(tr(" 5 days" ),this,SLOT(setSyncPostsDelay())) ; actnn->setData(QVariant( 5)) ; if(current_sync_time == 5) { actnn->setEnabled(false);actnn->setIcon(QIcon(":/images/start.png"));}
actnn = ctxMenu2->addAction(tr(" 2 weeks" ),this,SLOT(setSyncPostsDelay())) ; actnn->setData(QVariant( 15)) ; if(current_sync_time == 15) { actnn->setEnabled(false);actnn->setIcon(QIcon(":/images/start.png"));}
actnn = ctxMenu2->addAction(tr(" 1 month" ),this,SLOT(setSyncPostsDelay())) ; actnn->setData(QVariant( 30)) ; if(current_sync_time == 30) { actnn->setEnabled(false);actnn->setIcon(QIcon(":/images/start.png"));}
actnn = ctxMenu2->addAction(tr(" 3 months" ),this,SLOT(setSyncPostsDelay())) ; actnn->setData(QVariant( 90)) ; if(current_sync_time == 90) { actnn->setEnabled(false);actnn->setIcon(QIcon(":/images/start.png"));}
actnn = ctxMenu2->addAction(tr(" 6 months" ),this,SLOT(setSyncPostsDelay())) ; actnn->setData(QVariant(180)) ; if(current_sync_time ==180) { actnn->setEnabled(false);actnn->setIcon(QIcon(":/images/start.png"));}
actnn = ctxMenu2->addAction(tr(" 1 year " ),this,SLOT(setSyncPostsDelay())) ; actnn->setData(QVariant(372)) ; if(current_sync_time ==372) { actnn->setEnabled(false);actnn->setIcon(QIcon(":/images/start.png"));}
actnn = ctxMenu2->addAction(tr(" Indefinitly"),this,SLOT(setSyncPostsDelay())) ; actnn->setData(QVariant( 0)) ; if(current_sync_time == 0) { actnn->setEnabled(false);actnn->setIcon(QIcon(":/images/start.png"));}
ctxMenu2 = contextMnu.addMenu(tr("Store posts for at most...")) ;
actnn = ctxMenu2->addAction(tr(" 5 days" ),this,SLOT(setStorePostsDelay())) ; actnn->setData(QVariant( 5)) ; if(current_store_time == 5) { actnn->setEnabled(false);actnn->setIcon(QIcon(":/images/start.png"));}
actnn = ctxMenu2->addAction(tr(" 2 weeks" ),this,SLOT(setStorePostsDelay())) ; actnn->setData(QVariant( 15)) ; if(current_store_time == 15) { actnn->setEnabled(false);actnn->setIcon(QIcon(":/images/start.png"));}
actnn = ctxMenu2->addAction(tr(" 1 month" ),this,SLOT(setStorePostsDelay())) ; actnn->setData(QVariant( 30)) ; if(current_store_time == 30) { actnn->setEnabled(false);actnn->setIcon(QIcon(":/images/start.png"));}
actnn = ctxMenu2->addAction(tr(" 3 months" ),this,SLOT(setStorePostsDelay())) ; actnn->setData(QVariant( 90)) ; if(current_store_time == 90) { actnn->setEnabled(false);actnn->setIcon(QIcon(":/images/start.png"));}
actnn = ctxMenu2->addAction(tr(" 6 months" ),this,SLOT(setStorePostsDelay())) ; actnn->setData(QVariant(180)) ; if(current_store_time ==180) { actnn->setEnabled(false);actnn->setIcon(QIcon(":/images/start.png"));}
actnn = ctxMenu2->addAction(tr(" 1 year " ),this,SLOT(setStorePostsDelay())) ; actnn->setData(QVariant(372)) ; if(current_store_time ==372) { actnn->setEnabled(false);actnn->setIcon(QIcon(":/images/start.png"));}
actnn = ctxMenu2->addAction(tr(" Indefinitly"),this,SLOT(setStorePostsDelay())) ; actnn->setData(QVariant( 0)) ; if(current_store_time == 0) { actnn->setEnabled(false);actnn->setIcon(QIcon(":/images/start.png"));}
if (shareKeyType()) {
action = contextMnu.addAction(QIcon(IMAGE_SHARE), tr("Share publish permissions"), this, SLOT(sharePublishKey()));
action->setEnabled(!mGroupId.isNull() && isPublisher);
}
if (getLinkType() != RetroShareLink::TYPE_UNKNOWN) {
action = contextMnu.addAction(QIcon(IMAGE_COPYLINK), tr("Copy RetroShare Link"), this, SLOT(copyGroupLink()));
action->setEnabled(!mGroupId.isNull());
}
contextMnu.addSeparator();
action = contextMnu.addAction(QIcon(":/images/message-mail-read.png"), tr("Mark all as read"), this, SLOT(markMsgAsRead()));
action->setEnabled (!mGroupId.isNull() && isSubscribed);
action = contextMnu.addAction(QIcon(":/images/message-mail.png"), tr("Mark all as unread"), this, SLOT(markMsgAsUnread()));
action->setEnabled (!mGroupId.isNull() && isSubscribed);
/* Add special actions */
QList<QAction*> actions;
groupTreeCustomActions(mGroupId, subscribeFlags, actions);
if (!actions.isEmpty()) {
contextMnu.addSeparator();
contextMnu.addAction(QIcon(icon(ICON_NEW)), text(TEXT_NEW), this, SLOT(newGroup()));
action = contextMnu.addAction(QIcon(IMAGE_INFO), tr("Show Details"), this, SLOT(showGroupDetails()));
action->setEnabled (!mGroupId.isNull());
action = contextMnu.addAction(QIcon(IMAGE_EDIT), tr("Edit Details"), this, SLOT(editGroupDetails()));
action->setEnabled (!mGroupId.isNull() && isAdmin);
uint32_t current_store_time = mInterface->getStoragePeriod(mGroupId)/86400 ;
uint32_t current_sync_time = mInterface->getSyncPeriod(mGroupId)/86400 ;
std::cerr << "Got sync=" << current_sync_time << ". store=" << current_store_time << std::endl;
QAction *actnn = NULL;
QMenu *ctxMenu2 = contextMnu.addMenu(tr("Synchronise posts of last...")) ;
actnn = ctxMenu2->addAction(tr(" 5 days" ),this,SLOT(setSyncPostsDelay())) ; actnn->setData(QVariant( 5)) ; if(current_sync_time == 5) { actnn->setEnabled(false);actnn->setIcon(QIcon(":/images/start.png"));}
actnn = ctxMenu2->addAction(tr(" 2 weeks" ),this,SLOT(setSyncPostsDelay())) ; actnn->setData(QVariant( 15)) ; if(current_sync_time == 15) { actnn->setEnabled(false);actnn->setIcon(QIcon(":/images/start.png"));}
actnn = ctxMenu2->addAction(tr(" 1 month" ),this,SLOT(setSyncPostsDelay())) ; actnn->setData(QVariant( 30)) ; if(current_sync_time == 30) { actnn->setEnabled(false);actnn->setIcon(QIcon(":/images/start.png"));}
actnn = ctxMenu2->addAction(tr(" 3 months" ),this,SLOT(setSyncPostsDelay())) ; actnn->setData(QVariant( 90)) ; if(current_sync_time == 90) { actnn->setEnabled(false);actnn->setIcon(QIcon(":/images/start.png"));}
actnn = ctxMenu2->addAction(tr(" 6 months" ),this,SLOT(setSyncPostsDelay())) ; actnn->setData(QVariant(180)) ; if(current_sync_time ==180) { actnn->setEnabled(false);actnn->setIcon(QIcon(":/images/start.png"));}
actnn = ctxMenu2->addAction(tr(" 1 year " ),this,SLOT(setSyncPostsDelay())) ; actnn->setData(QVariant(372)) ; if(current_sync_time ==372) { actnn->setEnabled(false);actnn->setIcon(QIcon(":/images/start.png"));}
actnn = ctxMenu2->addAction(tr(" Indefinitly"),this,SLOT(setSyncPostsDelay())) ; actnn->setData(QVariant( 0)) ; if(current_sync_time == 0) { actnn->setEnabled(false);actnn->setIcon(QIcon(":/images/start.png"));}
ctxMenu2 = contextMnu.addMenu(tr("Store posts for at most...")) ;
actnn = ctxMenu2->addAction(tr(" 5 days" ),this,SLOT(setStorePostsDelay())) ; actnn->setData(QVariant( 5)) ; if(current_store_time == 5) { actnn->setEnabled(false);actnn->setIcon(QIcon(":/images/start.png"));}
actnn = ctxMenu2->addAction(tr(" 2 weeks" ),this,SLOT(setStorePostsDelay())) ; actnn->setData(QVariant( 15)) ; if(current_store_time == 15) { actnn->setEnabled(false);actnn->setIcon(QIcon(":/images/start.png"));}
actnn = ctxMenu2->addAction(tr(" 1 month" ),this,SLOT(setStorePostsDelay())) ; actnn->setData(QVariant( 30)) ; if(current_store_time == 30) { actnn->setEnabled(false);actnn->setIcon(QIcon(":/images/start.png"));}
actnn = ctxMenu2->addAction(tr(" 3 months" ),this,SLOT(setStorePostsDelay())) ; actnn->setData(QVariant( 90)) ; if(current_store_time == 90) { actnn->setEnabled(false);actnn->setIcon(QIcon(":/images/start.png"));}
actnn = ctxMenu2->addAction(tr(" 6 months" ),this,SLOT(setStorePostsDelay())) ; actnn->setData(QVariant(180)) ; if(current_store_time ==180) { actnn->setEnabled(false);actnn->setIcon(QIcon(":/images/start.png"));}
actnn = ctxMenu2->addAction(tr(" 1 year " ),this,SLOT(setStorePostsDelay())) ; actnn->setData(QVariant(372)) ; if(current_store_time ==372) { actnn->setEnabled(false);actnn->setIcon(QIcon(":/images/start.png"));}
actnn = ctxMenu2->addAction(tr(" Indefinitly"),this,SLOT(setStorePostsDelay())) ; actnn->setData(QVariant( 0)) ; if(current_store_time == 0) { actnn->setEnabled(false);actnn->setIcon(QIcon(":/images/start.png"));}
if (shareKeyType()) {
action = contextMnu.addAction(QIcon(IMAGE_SHARE), tr("Share publish permissions"), this, SLOT(sharePublishKey()));
action->setEnabled(!mGroupId.isNull() && isPublisher);
}
if (getLinkType() != RetroShareLink::TYPE_UNKNOWN) {
action = contextMnu.addAction(QIcon(IMAGE_COPYLINK), tr("Copy RetroShare Link"), this, SLOT(copyGroupLink()));
action->setEnabled(!mGroupId.isNull());
}
contextMnu.addSeparator();
action = contextMnu.addAction(QIcon(":/images/message-mail-read.png"), tr("Mark all as read"), this, SLOT(markMsgAsRead()));
action->setEnabled (!mGroupId.isNull() && isSubscribed);
action = contextMnu.addAction(QIcon(":/images/message-mail.png"), tr("Mark all as unread"), this, SLOT(markMsgAsUnread()));
action->setEnabled (!mGroupId.isNull() && isSubscribed);
/* Add special actions */
QList<QAction*> actions;
groupTreeCustomActions(mGroupId, subscribeFlags, actions);
if (!actions.isEmpty()) {
contextMnu.addSeparator();
contextMnu.addActions(actions);
}
contextMnu.addActions(actions);
}
//Add Standard Menu
@ -594,7 +702,7 @@ bool GxsGroupFrameDialog::navigate(const RsGxsGroupId &groupId, const RsGxsMessa
return false;
}
changedGroup(groupIdString);
changedCurrentGroup(groupIdString);
/* search exisiting tab */
GxsMessageFrameWidget *msgWidget = messageWidget(mGroupId, false);
@ -655,7 +763,7 @@ GxsCommentDialog *GxsGroupFrameDialog::commentWidget(const RsGxsMessageId& msgId
return NULL;
}
void GxsGroupFrameDialog::changedGroup(const QString &groupId)
void GxsGroupFrameDialog::changedCurrentGroup(const QString &groupId)
{
if (mInFill) {
return;
@ -798,7 +906,7 @@ void GxsGroupFrameDialog::groupInfoToGroupItemInfo(const RsGroupMetaData &groupI
}
}
void GxsGroupFrameDialog::insertGroupsData(const std::list<RsGroupMetaData> &groupList, const RsUserdata *userdata)
void GxsGroupFrameDialog::insertGroupsData(const std::map<RsGxsGroupId,RsGroupMetaData> &groupList, const RsUserdata *userdata)
{
if (!mInitialized) {
return;
@ -806,20 +914,18 @@ void GxsGroupFrameDialog::insertGroupsData(const std::list<RsGroupMetaData> &gro
mInFill = true;
std::list<RsGroupMetaData>::const_iterator it;
QList<GroupItemInfo> adminList;
QList<GroupItemInfo> subList;
QList<GroupItemInfo> popList;
QList<GroupItemInfo> otherList;
std::multimap<uint32_t, GroupItemInfo> popMap;
for (it = groupList.begin(); it != groupList.end(); ++it) {
for (auto it = groupList.begin(); it != groupList.end(); ++it) {
/* sort it into Publish (Own), Subscribed, Popular and Other */
uint32_t flags = it->mSubscribeFlags;
uint32_t flags = it->second.mSubscribeFlags;
GroupItemInfo groupItemInfo;
groupInfoToGroupItemInfo(*it, groupItemInfo, userdata);
groupInfoToGroupItemInfo(it->second, groupItemInfo, userdata);
if (IS_GROUP_SUBSCRIBED(flags))
{
@ -836,7 +942,7 @@ void GxsGroupFrameDialog::insertGroupsData(const std::list<RsGroupMetaData> &gro
else
{
//popMap.insert(std::make_pair(it->mPop, groupItemInfo)); /* rate the others by popularity */
popMap.insert(std::make_pair(it->mLastPost, groupItemInfo)); /* rate the others by time of last post */
popMap.insert(std::make_pair(it->second.mLastPost, groupItemInfo)); /* rate the others by time of last post */
}
}
@ -947,9 +1053,12 @@ void GxsGroupFrameDialog::loadGroupSummary(const uint32_t &token)
RsUserdata *userdata = NULL;
loadGroupSummaryToken(token, groupInfo, userdata);
mCachedGroupMetas = groupInfo ;
mCachedGroupMetas.clear();
for(auto it(groupInfo.begin());it!=groupInfo.end();++it)
mCachedGroupMetas[(*it).mGroupId] = *it;
insertGroupsData(groupInfo, userdata);
insertGroupsData(mCachedGroupMetas, userdata);
updateSearchResults();
mStateHelper->setLoading(TOKEN_TYPE_GROUP_SUMMARY, false);
@ -1083,3 +1192,41 @@ void GxsGroupFrameDialog::loadRequest(const TokenQueue *queue, const TokenReques
}
}
}
TurtleRequestId GxsGroupFrameDialog::distantSearch(const QString& search_string) // this should be overloaded in the child class
{
std::cerr << "Searching for \"" << search_string.toStdString() << "\". Function is not overloaded, so nothing will happen." << std::endl;
return 0;
}
void GxsGroupFrameDialog::searchNetwork(const QString& search_string)
{
if(search_string.isNull())
return ;
uint32_t request_id = distantSearch(search_string);
if(request_id == 0)
return ;
mSearchGroupsItems[request_id] = ui->groupTreeWidget->addSearchItem(tr("Search for")+ " \"" + search_string + "\"",(uint32_t)request_id,QIcon(icon(ICON_SEARCH)));
}
void GxsGroupFrameDialog::distantRequestGroupData()
{
QAction *action = dynamic_cast<QAction*>(sender()) ;
if(!action)
return ;
RsGxsGroupId group_id(action->data().toString().toStdString());
if(group_id.isNull())
{
std::cerr << "Cannot retrieve group! Group id is null!" << std::endl;
}
std::cerr << "Explicit request for group " << group_id << std::endl;
checkRequestGroup(group_id) ;
}

View File

@ -67,11 +67,12 @@ public:
ICON_SUBSCRIBED_GROUP,
ICON_POPULAR_GROUP,
ICON_OTHER_GROUP,
ICON_SEARCH,
ICON_DEFAULT
};
public:
GxsGroupFrameDialog(RsGxsIfaceHelper *ifaceImpl, QWidget *parent = 0);
GxsGroupFrameDialog(RsGxsIfaceHelper *ifaceImpl, QWidget *parent = 0,bool allow_dist_sync=false);
virtual ~GxsGroupFrameDialog();
bool navigate(const RsGxsGroupId &groupId, const RsGxsMessageId& msgId);
@ -81,7 +82,7 @@ public:
virtual QString getHelpString() const =0;
virtual void getGroupList(std::list<RsGroupMetaData>& groups) ;
virtual void getGroupList(std::map<RsGxsGroupId,RsGroupMetaData> &groups) ;
protected:
virtual void showEvent(QShowEvent *event);
@ -94,6 +95,7 @@ protected:
virtual RetroShareLink::enumType getLinkType() = 0;
virtual GroupFrameSettings::Type groupFrameSettingsType() { return GroupFrameSettings::Nothing; }
virtual void groupInfoToGroupItemInfo(const RsGroupMetaData &groupInfo, GroupItemInfo &groupItemInfo, const RsUserdata *userdata);
virtual void checkRequestGroup(const RsGxsGroupId& /* grpId */) {} // overload this one in order to retrieve full group data when the group is browsed
private slots:
void todo();
@ -106,8 +108,9 @@ private slots:
void restoreGroupKeys();
void newGroup();
void distantRequestGroupData();
void changedGroup(const QString &groupId);
void changedCurrentGroup(const QString &groupId);
void groupTreeMiddleButtonClicked(QTreeWidgetItem *item);
void openInNewTab();
void messageTabCloseRequested(int index);
@ -130,10 +133,15 @@ private slots:
void loadComment(const RsGxsGroupId &grpId, const QVector<RsGxsMessageId>& msg_versions,const RsGxsMessageId &most_recent_msgId, const QString &title);
void searchNetwork(const QString &search_string) ;
void removeAllSearches();
void removeCurrentSearch();
private:
virtual QString text(TextType type) = 0;
virtual QString icon(IconType type) = 0;
virtual QString settingsGroupName() = 0;
virtual TurtleRequestId distantSearch(const QString& search_string) ;
virtual GxsGroupDialog *createNewGroupDialog(TokenQueue *tokenQueue) = 0;
virtual GxsGroupDialog *createGroupDialog(TokenQueue *tokenQueue, RsTokenService *tokenService, GxsGroupDialog::Mode mode, RsGxsGroupId groupId) = 0;
@ -142,10 +150,12 @@ private:
virtual void groupTreeCustomActions(RsGxsGroupId /*grpId*/, int /*subscribeFlags*/, QList<QAction*> &/*actions*/) {}
virtual RsGxsCommentService *getCommentService() { return NULL; }
virtual QWidget *createCommentHeaderWidget(const RsGxsGroupId &/*grpId*/, const RsGxsMessageId &/*msgId*/) { return NULL; }
virtual bool getDistantSearchResults(TurtleRequestId /* id */, std::map<RsGxsGroupId,RsGxsGroupSummary>& /* group_infos */){ return false ;}
void initUi();
void updateMessageSummaryList(RsGxsGroupId groupId);
void updateSearchResults();
void openGroupInNewTab(const RsGxsGroupId &groupId);
void groupSubscribe(bool subscribe);
@ -153,7 +163,7 @@ private:
void processSettings(bool load);
// New Request/Response Loading Functions.
void insertGroupsData(const std::list<RsGroupMetaData> &groupList, const RsUserdata *userdata);
void insertGroupsData(const std::map<RsGxsGroupId, RsGroupMetaData> &groupList, const RsUserdata *userdata);
void requestGroupSummary();
void loadGroupSummary(const uint32_t &token);
@ -180,6 +190,7 @@ protected:
private:
bool mInitialized;
bool mInFill;
bool mDistSyncAllowed;
QString mSettingsName;
RsGxsGroupId mGroupId;
RsGxsIfaceHelper *mInterface;
@ -200,7 +211,10 @@ private:
/** Qt Designer generated object */
Ui::GxsGroupFrameDialog *ui;
std::list<RsGroupMetaData> mCachedGroupMetas;
std::map<RsGxsGroupId,RsGroupMetaData> mCachedGroupMetas;
std::map<uint32_t,QTreeWidgetItem*> mSearchGroupsItems ;
std::map<uint32_t,std::set<RsGxsGroupId> > mKnownGroups;
};
#endif

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>619</width>
<height>420</height>
<height>493</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
@ -38,7 +38,16 @@
<enum>QFrame::Sunken</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="margin">
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>

View File

@ -57,6 +57,7 @@ protected:
virtual void groupNameChanged(const QString &/*name*/) {}
virtual void clearPosts() = 0;
virtual void blank() = 0;
virtual bool navigatePostItem(const RsGxsMessageId& msgId) = 0;
/* Thread functions */

View File

@ -72,21 +72,26 @@ bool GxsMessageFrameWidget::isWaiting()
void GxsMessageFrameWidget::setGroupId(const RsGxsGroupId &groupId)
{
if (mGroupId == groupId) {
if (!groupId.isNull()) {
return;
if (mGroupId == groupId && !groupId.isNull())
return;
if(!groupId.isNull())
{
mAcknowledgeReadStatusToken = 0;
if (mStateHelper->isLoading(mTokenTypeAcknowledgeReadStatus)) {
mStateHelper->setLoading(mTokenTypeAcknowledgeReadStatus, false);
emit waitingChanged(this);
}
mGroupId = groupId;
groupIdChanged();
}
mAcknowledgeReadStatusToken = 0;
if (mStateHelper->isLoading(mTokenTypeAcknowledgeReadStatus)) {
mStateHelper->setLoading(mTokenTypeAcknowledgeReadStatus, false);
emit waitingChanged(this);
}
mGroupId = groupId;
groupIdChanged();
else
{
mGroupId.clear();
blank(); // clear the displayed data, because no group is selected.
}
}
void GxsMessageFrameWidget::setAllMessagesRead(bool read)

View File

@ -43,6 +43,7 @@ public:
virtual void groupIdChanged() = 0;
virtual QString groupName(bool withUnreadCount) = 0;
virtual QIcon groupIcon() = 0;
virtual void blank() =0;
virtual bool navigate(const RsGxsMessageId& msgId) = 0;
virtual bool isLoading();
virtual bool isWaiting();

View File

@ -16,12 +16,19 @@ RsGxsUpdateBroadcastBase::RsGxsUpdateBroadcastBase(RsGxsIfaceHelper *ifaceImpl,
connect(mUpdateBroadcast, SIGNAL(changed()), this, SLOT(updateBroadcastChanged()));
connect(mUpdateBroadcast, SIGNAL(grpsChanged(std::list<RsGxsGroupId>, std::list<RsGxsGroupId>)), this, SLOT(updateBroadcastGrpsChanged(std::list<RsGxsGroupId>,std::list<RsGxsGroupId>)));
connect(mUpdateBroadcast, SIGNAL(msgsChanged(std::map<RsGxsGroupId,std::set<RsGxsMessageId> >, std::map<RsGxsGroupId,std::set<RsGxsMessageId> >)), this, SLOT(updateBroadcastMsgsChanged(std::map<RsGxsGroupId,std::set<RsGxsMessageId> >,std::map<RsGxsGroupId,std::set<RsGxsMessageId> >)));
connect(mUpdateBroadcast, SIGNAL(distantSearchResultsChanged(const std::list<TurtleRequestId>&)), this, SLOT(updateBroadcastDistantSearchResultsChanged(const std::list<TurtleRequestId>&)));
}
RsGxsUpdateBroadcastBase::~RsGxsUpdateBroadcastBase()
{
}
void RsGxsUpdateBroadcastBase::updateBroadcastDistantSearchResultsChanged(const std::list<TurtleRequestId>& ids)
{
for(auto it(ids.begin());it!=ids.end();++it)
mTurtleResults.insert(*it);
}
void RsGxsUpdateBroadcastBase::fillComplete()
{
mFillComplete = true;
@ -37,6 +44,9 @@ void RsGxsUpdateBroadcastBase::securedUpdateDisplay()
return;
}
// This is *bad* because if the connection is done asynchronously the client will call mGrpIds, mGrpIdsMeta, etc without the guarranty that the
// the structed havnt' been cleared in the mean time.
emit fillDisplay(mFillComplete);
mFillComplete = false;
@ -75,7 +85,7 @@ void RsGxsUpdateBroadcastBase::updateBroadcastChanged()
// The question to whether we should re=load when mGrpIds is not empty is still open. It's not harmful anyway.
// This should probably be decided by the service itself.
if (!mGrpIds.empty() || !mGrpIdsMeta.empty() /*|| !mMsgIds.empty()*/ || !mMsgIdsMeta.empty())
if (!mGrpIds.empty() || !mGrpIdsMeta.empty() /*|| !mMsgIds.empty()*/ || !mMsgIdsMeta.empty() || !mTurtleResults.empty())
mFillComplete = true ;
securedUpdateDisplay();

View File

@ -7,6 +7,8 @@ class QShowEvent;
class RsGxsIfaceHelper;
class RsGxsUpdateBroadcast;
typedef uint32_t TurtleRequestId ;
class RsGxsUpdateBroadcastBase : public QObject
{
friend class RsGxsUpdateBroadcastPage;
@ -25,6 +27,7 @@ public:
const std::map<RsGxsGroupId, std::set<RsGxsMessageId> > &getMsgIds() { return mMsgIds; }
const std::map<RsGxsGroupId, std::set<RsGxsMessageId> > &getMsgIdsMeta() { return mMsgIdsMeta; }
void getAllMsgIds(std::map<RsGxsGroupId, std::set<RsGxsMessageId> > &msgIds);
const std::set<TurtleRequestId>& getSearchResults() { return mTurtleResults ; }
protected:
void fillComplete();
@ -39,6 +42,7 @@ private slots:
void updateBroadcastChanged();
void updateBroadcastGrpsChanged(const std::list<RsGxsGroupId>& grpIds, const std::list<RsGxsGroupId> &grpIdsMeta);
void updateBroadcastMsgsChanged(const std::map<RsGxsGroupId, std::set<RsGxsMessageId> >& msgIds, const std::map<RsGxsGroupId, std::set<RsGxsMessageId> >& msgIdsMeta);
void updateBroadcastDistantSearchResultsChanged(const std::list<TurtleRequestId>& ids);
void securedUpdateDisplay();
private:
@ -49,4 +53,5 @@ private:
std::set<RsGxsGroupId> mGrpIdsMeta;
std::map<RsGxsGroupId, std::set<RsGxsMessageId> > mMsgIds;
std::map<RsGxsGroupId, std::set<RsGxsMessageId> > mMsgIdsMeta;
std::set<TurtleRequestId> mTurtleResults;
};

View File

@ -22,6 +22,11 @@ void RsGxsUpdateBroadcastPage::setUpdateWhenInvisible(bool update)
mBase->setUpdateWhenInvisible(update);
}
const std::set<TurtleRequestId>& RsGxsUpdateBroadcastPage::getSearchResults()
{
return mBase->getSearchResults();
}
const std::set<RsGxsGroupId> &RsGxsUpdateBroadcastPage::getGrpIdsMeta()
{
return mBase->getGrpIdsMeta();

View File

@ -13,6 +13,7 @@
class RsGxsIfaceHelper;
class RsGxsUpdateBroadcastBase;
typedef uint32_t TurtleRequestId ;
class RsGxsUpdateBroadcastPage : public MainPage
{
@ -30,6 +31,7 @@ public:
const std::map<RsGxsGroupId, std::set<RsGxsMessageId> > &getMsgIds();
const std::map<RsGxsGroupId, std::set<RsGxsMessageId> > &getMsgIdsMeta();
void getAllMsgIds(std::map<RsGxsGroupId, std::set<RsGxsMessageId> > &msgIds);
const std::set<TurtleRequestId>& getSearchResults();
protected:
virtual void showEvent(QShowEvent *event);

View File

@ -29,6 +29,10 @@ const std::set<RsGxsGroupId> &RsGxsUpdateBroadcastWidget::getGrpIds()
return mBase->getGrpIds();
}
const std::set<TurtleRequestId>& RsGxsUpdateBroadcastWidget::getSearchResults()
{
return mBase->getSearchResults();
}
const std::set<RsGxsGroupId> &RsGxsUpdateBroadcastWidget::getGrpIdsMeta()
{
return mBase->getGrpIdsMeta();

View File

@ -13,6 +13,7 @@
class RsGxsIfaceHelper;
class RsGxsUpdateBroadcastBase;
typedef uint32_t TurtleRequestId;
class RsGxsUpdateBroadcastWidget : public QWidget
{
@ -30,6 +31,7 @@ public:
const std::map<RsGxsGroupId, std::set<RsGxsMessageId> > &getMsgIds();
const std::map<RsGxsGroupId, std::set<RsGxsMessageId> > &getMsgIdsMeta();
void getAllMsgIds(std::map<RsGxsGroupId, std::set<RsGxsMessageId> > &msgIds);
const std::set<TurtleRequestId>& getSearchResults() ;
RsGxsIfaceHelper *interfaceHelper() { return mInterfaceHelper; }

View File

@ -47,7 +47,7 @@ public:
/** Constructor */
GxsChannelDialog::GxsChannelDialog(QWidget *parent)
: GxsGroupFrameDialog(rsGxsChannels, parent)
: GxsGroupFrameDialog(rsGxsChannels, parent,true)
{
}
@ -137,6 +137,8 @@ QString GxsChannelDialog::icon(IconType type)
return ":/images/folder_green.png";
case ICON_OTHER_GROUP:
return ":/images/folder_yellow.png";
case ICON_SEARCH:
return ":/images/find.png";
case ICON_DEFAULT:
return ":/images/channels.png";
}
@ -334,3 +336,24 @@ void GxsChannelDialog::groupInfoToGroupItemInfo(const RsGroupMetaData &groupInfo
groupItemInfo.icon = iconIt.value();
}
}
TurtleRequestId GxsChannelDialog::distantSearch(const QString& search_string)
{
return rsGxsChannels->turtleSearchRequest(search_string.toStdString()) ;
}
bool GxsChannelDialog::getDistantSearchResults(TurtleRequestId id, std::map<RsGxsGroupId,RsGxsGroupSummary>& group_infos)
{
return rsGxsChannels->retrieveDistantSearchResults(id,group_infos);
}
void GxsChannelDialog::checkRequestGroup(const RsGxsGroupId& grpId)
{
RsGxsChannelGroup distant_group;
if( rsGxsChannels->retrieveDistantGroup(grpId,distant_group)) // normally we should also check that the group meta is not already here.
{
std::cerr << "GxsChannelDialog::checkRequestGroup() sending turtle request for group data for group " << grpId << std::endl;
rsGxsChannels->turtleGroupRequest(grpId);
}
}

View File

@ -50,6 +50,10 @@ protected:
virtual GroupFrameSettings::Type groupFrameSettingsType() { return GroupFrameSettings::Channel; }
virtual QString getHelpString() const ;
virtual void groupInfoToGroupItemInfo(const RsGroupMetaData &groupInfo, GroupItemInfo &groupItemInfo, const RsUserdata *userdata);
virtual bool getDistantSearchResults(TurtleRequestId id, std::map<RsGxsGroupId,RsGxsGroupSummary>& group_infos);
virtual TurtleRequestId distantSearch(const QString& search_string) ;
virtual void checkRequestGroup(const RsGxsGroupId& grpId) ;
private slots:
void toggleAutoDownload();

View File

@ -596,6 +596,20 @@ void GxsChannelPostsWidget::clearPosts()
ui->fileWidget->clear();
}
void GxsChannelPostsWidget::blank()
{
mStateHelper->setWidgetEnabled(ui->postButton, false);
mStateHelper->setWidgetEnabled(ui->subscribeToolButton, false);
clearPosts();
groupNameChanged(QString());
ui->infoWidget->hide();
ui->feedWidget->show();
ui->fileWidget->hide();
}
bool GxsChannelPostsWidget::navigatePostItem(const RsGxsMessageId &msgId)
{
FeedItem *feedItem = ui->feedWidget->findGxsFeedItem(groupId(), msgId);
@ -643,12 +657,22 @@ bool GxsChannelPostsWidget::insertGroupData(const uint32_t &token, RsGroupMetaDa
std::vector<RsGxsChannelGroup> groups;
rsGxsChannels->getGroupData(token, groups);
if (groups.size() == 1)
if(groups.size() == 1)
{
insertChannelDetails(groups[0]);
metaData = groups[0].mMeta;
return true;
}
else
{
RsGxsChannelGroup distant_group;
if(rsGxsChannels->retrieveDistantGroup(groupId(),distant_group))
{
insertChannelDetails(distant_group);
metaData = distant_group.mMeta;
return true ;
}
}
return false;
}

View File

@ -73,6 +73,7 @@ protected:
virtual bool useThread() { return mUseThread; }
virtual void fillThreadCreatePost(const QVariant &post, bool related, int current, int count);
virtual bool navigatePostItem(const RsGxsMessageId& msgId);
virtual void blank() ;
/* GxsMessageFrameWidget */
virtual void setAllMessagesReadDo(bool read, uint32_t &token);

View File

@ -299,6 +299,28 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget
}
void GxsForumThreadWidget::blank()
{
ui->progressBar->hide();
ui->progressText->hide();
ui->postText->clear() ;
ui->by_label->setId(RsGxsId()) ;
ui->time_label->clear();
ui->lineRight->hide();
ui->lineLeft->hide();
ui->by_text_label->hide();
ui->by_label->hide();
ui->postText->setImageBlockWidget(ui->imageBlockWidget) ;
ui->postText->resetImagesStatus(Settings->getForumLoadEmbeddedImages());
ui->threadTreeWidget->clear();
ui->forumName->setText("");
mStateHelper->setWidgetEnabled(ui->newthreadButton, false);
mStateHelper->setWidgetEnabled(ui->previousButton, false);
mStateHelper->setWidgetEnabled(ui->nextButton, false);
ui->versions_CB->hide();
}
GxsForumThreadWidget::~GxsForumThreadWidget()
{
if (mFillThread) {

View File

@ -58,6 +58,7 @@ public:
// Callback for all Loads.
virtual void loadRequest(const TokenQueue *queue, const TokenRequest &req);
virtual void blank();
protected:
bool eventFilter(QObject *obj, QEvent *ev);

View File

@ -563,6 +563,11 @@ void NotifyQt::notifyChatCleared(const ChatId& chat_id)
emit chatCleared(chat_id);
}
void NotifyQt::notifyTurtleSearchResult(uint32_t search_id,const std::list<TurtleGxsInfo>& found_groups)
{
std::cerr << "(EE) missing code to handle GXS turtle search result." << std::endl;
}
void NotifyQt::notifyTurtleSearchResult(uint32_t search_id,const std::list<TurtleFileInfo>& files)
{
{

View File

@ -23,7 +23,9 @@ class MessengerWindow;
class ToasterItem;
class ToasterNotify;
class SignatureEventData ;
struct TurtleFileInfo;
struct TurtleGxsInfo;
class NotifyQt: public QObject, public NotifyClient
{
@ -47,6 +49,7 @@ class NotifyQt: public QObject, public NotifyClient
virtual void notifyCustomState(const std::string& peer_id, const std::string& status_string);
virtual void notifyHashingInfo(uint32_t type, const std::string& fileinfo);
virtual void notifyTurtleSearchResult(uint32_t search_id,const std::list<TurtleFileInfo>& found_files);
virtual void notifyTurtleSearchResult(uint32_t search_id,const std::list<TurtleGxsInfo>& found_groups);
virtual void notifyPeerHasNewAvatar(std::string peer_id) ;
virtual void notifyOwnAvatarChanged() ;
virtual void notifyChatLobbyEvent(uint64_t /* lobby id */, uint32_t /* event type */, const RsGxsId & /*nickname*/, const std::string& /* any string */) ;

View File

@ -1,7 +1,11 @@
#include <QObject>
#include <util/rsprint.h>
#include <retroshare/rsturtle.h>
#include <retroshare/rspeers.h>
#include <retroshare/rsgxstunnel.h>
#include <retroshare/rsservicecontrol.h>
#include <retroshare/rsidentity.h>
#include <retroshare/rsgxsdistsync.h>
#include "TurtleRouterDialog.h"
#include <QPainter>
#include <QStylePainter>
@ -240,19 +244,14 @@ QTreeWidgetItem *TurtleRouterDialog::findParentHashItem(const std::string& hash)
else
return items.front() ;
}
//=======================================================================================================================//
GxsTunnelsDialog::GxsTunnelsDialog(QWidget *parent)
TunnelStatisticsDialog::TunnelStatisticsDialog(QWidget *parent)
: RsAutoUpdatePage(2000,parent)
{
// setupUi(this) ;
m_bProcessSettings = false;
//float fontHeight = QFontMetricsF(font()).height();
//float fact = fontHeight/14.0;
maxWidth = 200 ;
maxHeight = 200 ;
@ -260,14 +259,13 @@ GxsTunnelsDialog::GxsTunnelsDialog(QWidget *parent)
processSettings(true);
}
GxsTunnelsDialog::~GxsTunnelsDialog()
TunnelStatisticsDialog::~TunnelStatisticsDialog()
{
// save settings
processSettings(false);
}
void GxsTunnelsDialog::processSettings(bool bLoad)
void TunnelStatisticsDialog::processSettings(bool bLoad)
{
m_bProcessSettings = true;
@ -284,7 +282,77 @@ void GxsTunnelsDialog::processSettings(bool bLoad)
m_bProcessSettings = false;
}
void GxsTunnelsDialog::updateDisplay()
QString TunnelStatisticsDialog::getPeerName(const RsPeerId &peer_id)
{
static std::map<RsPeerId, QString> names ;
std::map<RsPeerId,QString>::const_iterator it = names.find(peer_id) ;
if( it != names.end())
return it->second ;
else
{
RsPeerDetails detail ;
if(!rsPeers->getPeerDetails(peer_id,detail))
return tr("Unknown Peer");
return (names[peer_id] = QString::fromUtf8(detail.name.c_str())) ;
}
}
QString TunnelStatisticsDialog::getPeerName(const RsGxsId& gxs_id)
{
static std::map<RsGxsId, QString> names ;
std::map<RsGxsId,QString>::const_iterator it = names.find(gxs_id) ;
if( it != names.end())
return it->second ;
else
{
RsIdentityDetails detail ;
if(!rsIdentity->getIdDetails(gxs_id,detail))
return tr("Unknown Peer");
return (names[gxs_id] = QString::fromUtf8(detail.mNickname.c_str())) ;
}
}
QString TunnelStatisticsDialog::speedString(float f)
{
if(f < 1.0f)
return QString("0 B/s") ;
if(f < 1024.0f)
return QString::number((int)f)+" B/s" ;
return QString::number(f/1024.0,'f',2) + " KB/s";
}
void TunnelStatisticsDialog::paintEvent(QPaintEvent */*event*/)
{
QStylePainter(this).drawPixmap(0, 0, pixmap);
}
void TunnelStatisticsDialog::resizeEvent(QResizeEvent *event)
{
QRect TaskGraphRect = geometry();
maxWidth = TaskGraphRect.width();
maxHeight = TaskGraphRect.height() ;
QWidget::resizeEvent(event);
update();
}
//=======================================================================================================================//
GxsAuthenticatedTunnelsDialog::GxsAuthenticatedTunnelsDialog(QWidget *parent)
: TunnelStatisticsDialog(parent)
{
}
void GxsAuthenticatedTunnelsDialog::updateDisplay()
{
// Request info about ongoing tunnels
@ -334,8 +402,8 @@ void GxsTunnelsDialog::updateDisplay()
// draw...
painter.drawText(ox+4*cellx,oy+celly,tr("Tunnel ID: %1").arg(QString::fromStdString(tunnel_infos[i].tunnel_id.toStdString()))) ; oy += celly ;
painter.drawText(ox+6*cellx,oy+celly,tr("from: %1").arg(QString::fromStdString(tunnel_infos[i].source_gxs_id.toStdString()))) ; oy += celly ;
painter.drawText(ox+6*cellx,oy+celly,tr("to: %1").arg(QString::fromStdString(tunnel_infos[i].destination_gxs_id.toStdString()))) ; oy += celly ;
painter.drawText(ox+6*cellx,oy+celly,tr("from: %1 (%2)").arg(QString::fromStdString(tunnel_infos[i].source_gxs_id.toStdString())).arg(getPeerName(tunnel_infos[i].source_gxs_id))) ; oy += celly ;
painter.drawText(ox+6*cellx,oy+celly,tr("to: %1 (%2)").arg(QString::fromStdString(tunnel_infos[i].destination_gxs_id.toStdString())).arg(getPeerName(tunnel_infos[i].destination_gxs_id))) ; oy += celly ;
painter.drawText(ox+6*cellx,oy+celly,tr("status: %1").arg(QString::number(tunnel_infos[i].tunnel_status))) ; oy += celly ;
painter.drawText(ox+6*cellx,oy+celly,tr("total sent: %1 bytes").arg(QString::number(tunnel_infos[i].total_size_sent))) ; oy += celly ;
painter.drawText(ox+6*cellx,oy+celly,tr("total recv: %1 bytes").arg(QString::number(tunnel_infos[i].total_size_received))) ; oy += celly ;
@ -350,46 +418,197 @@ void GxsTunnelsDialog::updateDisplay()
maxHeight = std::max(oy,10*celly);
}
QString GxsTunnelsDialog::getPeerName(const RsPeerId &peer_id)
//=======================================================================================================================//
GxsNetTunnelsDialog::GxsNetTunnelsDialog(QWidget *parent)
: TunnelStatisticsDialog(parent)
{
static std::map<RsPeerId, QString> names ;
}
std::map<RsPeerId,QString>::const_iterator it = names.find(peer_id) ;
static QString getGroupStatusString(RsGxsNetTunnelGroupInfo::GroupStatus group_status)
{
switch(group_status)
{
default:
case RsGxsNetTunnelGroupInfo::RS_GXS_NET_TUNNEL_GRP_STATUS_UNKNOWN : return QObject::tr("Unknown") ;
case RsGxsNetTunnelGroupInfo::RS_GXS_NET_TUNNEL_GRP_STATUS_IDLE : return QObject::tr("Idle");
case RsGxsNetTunnelGroupInfo::RS_GXS_NET_TUNNEL_GRP_STATUS_VPIDS_AVAILABLE : return QObject::tr("Virtual peers available");
}
return QString();
}
if( it != names.end())
return it->second ;
else
static QString getGroupPolicyString(RsGxsNetTunnelGroupInfo::GroupPolicy group_policy)
{
switch(group_policy)
{
default:
case RsGxsNetTunnelGroupInfo::RS_GXS_NET_TUNNEL_GRP_POLICY_UNKNOWN : return QObject::tr("Unknown") ;
case RsGxsNetTunnelGroupInfo::RS_GXS_NET_TUNNEL_GRP_POLICY_PASSIVE : return QObject::tr("Passive") ;
case RsGxsNetTunnelGroupInfo::RS_GXS_NET_TUNNEL_GRP_POLICY_ACTIVE : return QObject::tr("Active") ;
case RsGxsNetTunnelGroupInfo::RS_GXS_NET_TUNNEL_GRP_POLICY_REQUESTING : return QObject::tr("Requesting peers") ;
}
return QString();
}
static QString getLastContactString(time_t last_contact)
{
time_t now = time(NULL);
if(last_contact == 0)
return QObject::tr("Never");
return QString::number(now - last_contact) + " secs ago" ;
}
static QString getServiceNameString(uint16_t service_id)
{
static RsPeerServiceInfo ownServices;
if(ownServices.mServiceList.find(service_id) == ownServices.mServiceList.end())
rsServiceControl->getOwnServices(ownServices);
return QString::fromUtf8(ownServices.mServiceList[service_id].mServiceName.c_str()) ;
}
static QString getVirtualPeerStatusString(uint8_t status)
{
switch(status)
{
RsPeerDetails detail ;
if(!rsPeers->getPeerDetails(peer_id,detail))
return tr("Unknown Peer");
return (names[peer_id] = QString::fromUtf8(detail.name.c_str())) ;
default:
case RsGxsNetTunnelVirtualPeerInfo::RS_GXS_NET_TUNNEL_VP_STATUS_UNKNOWN : return QObject::tr("Unknown") ;
case RsGxsNetTunnelVirtualPeerInfo::RS_GXS_NET_TUNNEL_VP_STATUS_TUNNEL_OK : return QObject::tr("Tunnel OK") ;
case RsGxsNetTunnelVirtualPeerInfo::RS_GXS_NET_TUNNEL_VP_STATUS_ACTIVE : return QObject::tr("Tunnel active") ;
}
return QString();
}
QString GxsTunnelsDialog::speedString(float f)
static QString getSideString(uint8_t side)
{
if(f < 1.0f)
return QString("0 B/s") ;
if(f < 1024.0f)
return QString::number((int)f)+" B/s" ;
return QString::number(f/1024.0,'f',2) + " KB/s";
return side?QObject::tr("Client"):QObject::tr("Server") ;
}
void GxsTunnelsDialog::paintEvent(QPaintEvent */*event*/)
static QString getMasterKeyString(const uint8_t *key,uint32_t size)
{
QStylePainter(this).drawPixmap(0, 0, pixmap);
return QString::fromStdString(RsUtil::BinToHex(key,size,10));
}
void GxsTunnelsDialog::resizeEvent(QResizeEvent *event)
void GxsNetTunnelsDialog::updateDisplay()
{
QRect TaskGraphRect = geometry();
maxWidth = TaskGraphRect.width();
maxHeight = TaskGraphRect.height() ;
// Request info about ongoing tunnels
QWidget::resizeEvent(event);
update();
std::map<RsGxsGroupId,RsGxsNetTunnelGroupInfo> groups; // groups on the client and server side
std::map<TurtleVirtualPeerId,RsGxsNetTunnelVirtualPeerId> turtle2gxsnettunnel; // convertion table from turtle to net tunnel virtual peer id
std::map<RsGxsNetTunnelVirtualPeerId, RsGxsNetTunnelVirtualPeerInfo> virtual_peers; // current virtual peers, which group they provide, and how to talk to them through turtle
Bias20Bytes bias;
rsGxsDistSync->getStatistics(groups,virtual_peers,turtle2gxsnettunnel,bias) ;
// RsGxsNetTunnelGroupInfo:
//
// enum GroupStatus {
// RS_GXS_NET_TUNNEL_GRP_STATUS_UNKNOWN = 0x00, // unknown status
// RS_GXS_NET_TUNNEL_GRP_STATUS_IDLE = 0x01, // no virtual peers requested, just waiting
// RS_GXS_NET_TUNNEL_GRP_STATUS_VPIDS_AVAILABLE = 0x02 // some virtual peers are available. Data can be read/written
// };
// enum GroupPolicy {
// RS_GXS_NET_TUNNEL_GRP_POLICY_UNKNOWN = 0x00, // nothing has been set
// RS_GXS_NET_TUNNEL_GRP_POLICY_PASSIVE = 0x01, // group is available for server side tunnels, but does not explicitely request tunnels
// RS_GXS_NET_TUNNEL_GRP_POLICY_ACTIVE = 0x02, // group will only explicitely request tunnels if none available
// RS_GXS_NET_TUNNEL_GRP_POLICY_REQUESTING = 0x03, // group explicitely requests tunnels
// };
//
// RsGxsNetTunnelGroupInfo() : group_policy(RS_GXS_NET_TUNNEL_GRP_POLICY_PASSIVE),group_status(RS_GXS_NET_TUNNEL_GRP_STATUS_IDLE),last_contact(0) {}
//
// GroupPolicy group_policy ;
// GroupStatus group_status ;
// time_t last_contact ;
// RsFileHash hash ;
// uint16_t service_id ;
// std::set<RsPeerId> virtual_peers ;
//
// struct RsGxsNetTunnelVirtualPeerInfo:
//
// enum { RS_GXS_NET_TUNNEL_VP_STATUS_UNKNOWN = 0x00, // unknown status.
// RS_GXS_NET_TUNNEL_VP_STATUS_TUNNEL_OK = 0x01, // tunnel has been established and we're waiting for virtual peer id
// RS_GXS_NET_TUNNEL_VP_STATUS_ACTIVE = 0x02 // virtual peer id is known. Data can transfer.
// };
//
// RsGxsNetTunnelVirtualPeerInfo() : vpid_status(RS_GXS_NET_TUNNEL_VP_STATUS_UNKNOWN), last_contact(0),side(0) { memset(encryption_master_key,0,32) ; }
// virtual ~RsGxsNetTunnelVirtualPeerInfo(){}
//
// uint8_t vpid_status ; // status of the peer
// time_t last_contact ; // last time some data was sent/recvd
// uint8_t side ; // client/server
// uint8_t encryption_master_key[32];
//
// RsPeerId turtle_virtual_peer_id ; // turtle peer to use when sending data to this vpid.
//
// RsGxsGroupId group_id ; // group that virtual peer is providing
// uint16_t service_id ; // this is used for checkng consistency of the incoming data
// update the pixmap
//
// now draw the shit
QPixmap tmppixmap(maxWidth, maxHeight);
tmppixmap.fill(Qt::transparent);
//setFixedHeight(maxHeight);
QPainter painter(&tmppixmap);
painter.initFrom(this);
// extracts the height of the fonts in pixels. This is used to calibrate the size of the objects to draw.
float fontHeight = QFontMetricsF(font()).height();
float fact = fontHeight/14.0;
int cellx = 6*fact ;
int celly = (10+4)*fact ;
int ox=5*fact,oy=5*fact ;
painter.setPen(QColor::fromRgb(0,0,0)) ;
painter.drawText(ox+2*cellx,oy+celly,tr("Random Bias: %1").arg(getMasterKeyString(bias.toByteArray(),20))) ; oy += celly ;
painter.drawText(ox+2*cellx,oy+celly,tr("GXS Groups:")) ; oy += celly ;
for(auto it(groups.begin());it!=groups.end();++it)
{
painter.drawText(ox+4*cellx,oy+celly,tr("Service: %1 (%2) - Group ID: %3,\t policy: %4, \tstatus: %5, \tlast contact: %6")
.arg(QString::number(it->second.service_id))
.arg(getServiceNameString(it->second.service_id))
.arg(QString::fromStdString(it->first.toStdString()))
.arg(getGroupPolicyString(it->second.group_policy))
.arg(getGroupStatusString(it->second.group_status))
.arg(getLastContactString(it->second.last_contact))
),oy+=celly ;
for(auto it2(it->second.virtual_peers.begin());it2!=it->second.virtual_peers.end();++it2)
{
auto it4 = turtle2gxsnettunnel.find(*it2) ;
if(it4 != turtle2gxsnettunnel.end())
{
auto it3 = virtual_peers.find(it4->second) ;
if(virtual_peers.end() != it3)
painter.drawText(ox+6*cellx,oy+celly,tr("Peer: %1:\tstatus: %2/%3, \tlast contact: %4, \tMaster key: %5.")
.arg(QString::fromStdString((*it2).toStdString()))
.arg(getVirtualPeerStatusString(it3->second.vpid_status))
.arg(getSideString(it3->second.side))
.arg(getLastContactString(it3->second.last_contact))
.arg(getMasterKeyString(it3->second.encryption_master_key,32))
),oy+=celly ;
}
else
painter.drawText(ox+6*cellx,oy+celly,tr("Peer: %1: no information available")
.arg(QString::fromStdString((*it2).toStdString()))
),oy+=celly;
}
}
oy += celly ;
pixmap = tmppixmap;
maxHeight = std::max(oy,10*celly);
}

View File

@ -37,29 +37,55 @@ class TurtleRouterDialog: public RsAutoUpdatePage, public Ui::TurtleRouterDialog
} ;
class GxsTunnelsDialog: public RsAutoUpdatePage
class TunnelStatisticsDialog: public RsAutoUpdatePage
{
Q_OBJECT
public:
GxsTunnelsDialog(QWidget *parent = NULL) ;
~GxsTunnelsDialog();
TunnelStatisticsDialog(QWidget *parent = NULL) ;
~TunnelStatisticsDialog();
// Cache for peer names.
static QString getPeerName(const RsPeerId &peer_id) ;
static QString getPeerName(const RsGxsId& gxs_id);
protected:
virtual void paintEvent(QPaintEvent *);
virtual void resizeEvent(QResizeEvent *event);
int maxWidth ;
int maxHeight ;
QPixmap pixmap;
private:
void processSettings(bool bLoad);
bool m_bProcessSettings;
static QString speedString(float f);
virtual void updateDisplay() ;
int maxWidth ;
int maxHeight ;
QPixmap pixmap;
virtual void updateDisplay() =0;
} ;
class GxsAuthenticatedTunnelsDialog: public TunnelStatisticsDialog
{
Q_OBJECT
public:
GxsAuthenticatedTunnelsDialog(QWidget *parent = NULL) ;
~GxsAuthenticatedTunnelsDialog() {}
private:
virtual void updateDisplay() ;
} ;
class GxsNetTunnelsDialog: public TunnelStatisticsDialog
{
Q_OBJECT
public:
GxsNetTunnelsDialog(QWidget *parent = NULL) ;
~GxsNetTunnelsDialog() {}
private:
virtual void updateDisplay() ;
} ;

View File

@ -195,11 +195,13 @@ TurtleRouterStatistics::TurtleRouterStatistics(QWidget *parent)
_tunnel_statistics_F->setFrameStyle(QFrame::NoFrame);
_tunnel_statistics_F->setFocusPolicy(Qt::NoFocus);
routertabWidget->addTab(new TurtleRouterDialog(),QString(tr("Anonymous tunnels")));
routertabWidget->addTab(new GxsTunnelsDialog(),QString(tr("Authenticated tunnels")));
routertabWidget->addTab(new TurtleRouterDialog(), QString(tr("File transfer tunnels")));
routertabWidget->addTab(new GxsAuthenticatedTunnelsDialog(),QString(tr("Authenticated tunnels")));
routertabWidget->addTab(new GxsNetTunnelsDialog(), QString(tr("GXS sync tunnels") ));
float fontHeight = QFontMetricsF(font()).height();
float fact = fontHeight/14.0;
float fontHeight = QFontMetricsF(font()).height();
float fact = fontHeight/14.0;
frmGraph->setMinimumHeight(200*fact);
// load settings

View File

@ -79,5 +79,8 @@ void RsGxsUpdateBroadcast::onChangesReceived(const RsGxsChanges& changes)
emit grpsChanged(changes.mGrps, changes.mGrpsMeta);
}
if(!changes.mDistantSearchReqs.empty())
emit distantSearchResultsChanged(changes.mDistantSearchReqs) ;
emit changed();
}

View File

@ -8,6 +8,8 @@
class RsGxsIfaceHelper;
class RsGxsChanges;
typedef uint32_t TurtleRequestId ;
class RsGxsUpdateBroadcast : public QObject
{
Q_OBJECT
@ -21,6 +23,7 @@ signals:
void changed();
void msgsChanged(const std::map<RsGxsGroupId, std::set<RsGxsMessageId> >& msgIds, const std::map<RsGxsGroupId, std::set<RsGxsMessageId> >& msgIdsMeta);
void grpsChanged(const std::list<RsGxsGroupId>& grpIds, const std::list<RsGxsGroupId>& grpIdsMeta);
void distantSearchResultsChanged(const std::list<TurtleRequestId>& reqs);
private slots:
void onChangesReceived(const RsGxsChanges& changes);

View File

@ -10,6 +10,8 @@
CONFIG *= retroshare_gui
no_retroshare_gui:CONFIG -= retroshare_gui
CONFIG *= gxsdistsync
# To disable RetroShare-nogui append the following
# assignation to qmake command line "CONFIG+=no_retroshare_nogui"
CONFIG *= retroshare_nogui
@ -254,6 +256,7 @@ defineReplace(linkDynamicLibs) {
## RS_THREAD_LIB String viariable containing the name of the multi threading
## library to use (pthread, "") it usually depend on platform.
gxsdistsync:DEFINES *= RS_USE_GXS_DISTANT_SYNC
wikipoos:DEFINES *= RS_USE_WIKI
rs_gxs:DEFINES *= RS_ENABLE_GXS
libresapilocalserver:DEFINES *= LIBRESAPI_LOCAL_SERVER
@ -476,6 +479,7 @@ macx-* {
RS_UPNP_LIB = miniupnpc
}
## Retrocompatibility assignations, get rid of this ASAP
isEmpty(BIN_DIR) : BIN_DIR = $${RS_BIN_DIR}
isEmpty(INC_DIR) : INC_DIR = $${RS_INCLUDE_DIR}