diff --git a/libretroshare/src/ft/ftcontroller.cc b/libretroshare/src/ft/ftcontroller.cc index f462e0e34..7a83daaab 100644 --- a/libretroshare/src/ft/ftcontroller.cc +++ b/libretroshare/src/ft/ftcontroller.cc @@ -47,6 +47,7 @@ #include "ft/ftsearch.h" #include "ft/ftdatamultiplex.h" #include "ft/ftextralist.h" +#include "ft/ftserver.h" #include "turtle/p3turtle.h" @@ -102,6 +103,7 @@ ftController::ftController(CacheStrapper *cs, ftDataMultiplex *dm, std::string / last_clean_time(0), mDataplex(dm), mTurtle(NULL), + mFtServer(NULL), ctrlMutex("ftController"), doneMutex("ftController"), mFtActive(false), @@ -112,10 +114,9 @@ ftController::ftController(CacheStrapper *cs, ftDataMultiplex *dm, std::string / /* TODO */ } -void ftController::setTurtleRouter(p3turtle *pt) -{ - mTurtle = pt ; -} +void ftController::setTurtleRouter(p3turtle *pt) { mTurtle = pt ; } +void ftController::setFtServer(ftServer *ft) { mFtServer = ft ; } + void ftController::setFtSearchNExtra(ftSearch *search, ftExtraList *list) { mSearch = search; @@ -646,7 +647,7 @@ void ftController::locked_checkQueueElement(uint32_t pos) _queue[pos]->mState = ftFileControl::DOWNLOADING ; if(_queue[pos]->mFlags & RS_FILE_REQ_ANONYMOUS_ROUTING) - mTurtle->monitorFileTunnels(_queue[pos]->mName,_queue[pos]->mHash,_queue[pos]->mSize) ; + mTurtle->monitorTunnels(_queue[pos]->mHash,mFtServer) ; } if(pos >= _max_active_downloads && _queue[pos]->mState != ftFileControl::QUEUED && _queue[pos]->mState != ftFileControl::PAUSED) @@ -655,7 +656,7 @@ void ftController::locked_checkQueueElement(uint32_t pos) _queue[pos]->mCreator->closeFile() ; if(_queue[pos]->mFlags & RS_FILE_REQ_ANONYMOUS_ROUTING) - mTurtle->stopMonitoringFileTunnels(_queue[pos]->mHash) ; + mTurtle->stopMonitoringTunnels(_queue[pos]->mHash) ; } } @@ -899,7 +900,7 @@ bool ftController::completeFile(std::string hash) mDownloads.erase(it); if(flags & RS_FILE_REQ_ANONYMOUS_ROUTING) - mTurtle->stopMonitoringFileTunnels(hash_to_suppress) ; + mTurtle->stopMonitoringTunnels(hash_to_suppress) ; } /******* UNLOCKED ********/ @@ -1264,7 +1265,7 @@ bool ftController::FileRequest(const std::string& fname, const std::string& has // We check that flags are consistent. if(flags & RS_FILE_REQ_ANONYMOUS_ROUTING) - mTurtle->monitorFileTunnels(fname,hash,size) ; + mTurtle->monitorTunnels(hash,mFtServer) ; bool assume_availability = flags & RS_FILE_REQ_CACHE ; // assume availability for cache files @@ -1365,7 +1366,7 @@ bool ftController::setChunkStrategy(const std::string& hash,FileChunksInfo::Chun bool ftController::FileCancel(const std::string& hash) { - rsTurtle->stopMonitoringFileTunnels(hash) ; + rsTurtle->stopMonitoringTunnels(hash) ; #ifdef CONTROL_DEBUG std::cerr << "ftController::FileCancel" << std::endl; diff --git a/libretroshare/src/ft/ftcontroller.h b/libretroshare/src/ft/ftcontroller.h index 8494b2b82..bef432187 100644 --- a/libretroshare/src/ft/ftcontroller.h +++ b/libretroshare/src/ft/ftcontroller.h @@ -42,6 +42,7 @@ class ftFileCreator; class ftTransferModule; class ftFileProvider; class ftSearch; +class ftServer; class ftExtraList; class ftDataMultiplex; class p3turtle ; @@ -119,6 +120,7 @@ class ftController: public CacheTransfer, public RsThread, public pqiMonitor, pu void setFtSearchNExtra(ftSearch *, ftExtraList *); void setTurtleRouter(p3turtle *) ; + void setFtServer(ftServer *) ; bool activate(); bool isActiveAndNoPending(); @@ -234,6 +236,7 @@ class ftController: public CacheTransfer, public RsThread, public pqiMonitor, pu ftDataMultiplex *mDataplex; ftExtraList *mExtraList; p3turtle *mTurtle ; + ftServer *mFtServer ; RsMutex ctrlMutex; diff --git a/libretroshare/src/ft/ftdatamultiplex.cc b/libretroshare/src/ft/ftdatamultiplex.cc index bcc6c815c..6bbd32f30 100644 --- a/libretroshare/src/ft/ftdatamultiplex.cc +++ b/libretroshare/src/ft/ftdatamultiplex.cc @@ -1085,7 +1085,7 @@ bool ftDataMultiplex::locked_handleServerRequest(ftFileProvider *provider, std::string peerId, std::string hash, uint64_t size, uint64_t offset, uint32_t chunksize) { - if(chunksize > std::min(size,uint64_t(10*1024*1024))) + if(chunksize > uint32_t(10*1024*1024)) { std::cerr << "Warning: peer " << peerId << " is asking a large chunk (s=" << chunksize << ") for hash " << hash << ", filesize=" << size << ". This is unexpected." << std::endl ; return false ; diff --git a/libretroshare/src/ft/ftfileprovider.cc b/libretroshare/src/ft/ftfileprovider.cc index c17d291c6..775e368b0 100644 --- a/libretroshare/src/ft/ftfileprovider.cc +++ b/libretroshare/src/ft/ftfileprovider.cc @@ -153,6 +153,12 @@ bool ftFileProvider::getFileData(const std::string& peer_id,uint64_t offset, uin * FIXME: Warning of comparison between unsigned and signed int? */ + if(offset >= mSize) + { + std::cerr << "ftFileProvider::getFileData(): request (" << offset << ") exceeds file size (" << mSize << "! " << std::endl; + return false ; + } + uint32_t data_size = chunk_size; uint64_t base_loc = offset; diff --git a/libretroshare/src/ft/ftserver.cc b/libretroshare/src/ft/ftserver.cc index 81fe25a7e..864d9c52f 100644 --- a/libretroshare/src/ft/ftserver.cc +++ b/libretroshare/src/ft/ftserver.cc @@ -28,8 +28,10 @@ #include "util/rsdebug.h" #include "util/rsdir.h" #include "retroshare/rstypes.h" +#include "retroshare/rspeers.h" const int ftserverzone = 29539; +#include "ft/ftturtlefiletransferitem.h" #include "ft/ftserver.h" #include "ft/ftextralist.h" #include "ft/ftfilesearch.h" @@ -153,6 +155,9 @@ void ftServer::connectToTurtleRouter(p3turtle *fts) mTurtleRouter = fts ; mFtController->setTurtleRouter(fts) ; + mFtController->setFtServer(this) ; + + mTurtleRouter->registerTunnelService(this) ; } void ftServer::StartupThreads() @@ -450,6 +455,77 @@ bool ftServer::FileDetails(const std::string &hash, FileSearchFlags hintflags, F return false; } +RsTurtleGenericTunnelItem *ftServer::deserialiseItem(void *data,uint32_t size) const +{ + uint32_t rstype = getRsItemId(data); + +#ifdef SERVER_DEBUG + std::cerr << "p3turtle: deserialising packet: " << std::endl ; +#endif +#ifdef SERVER_DEBUG + if ((RS_PKT_VERSION_SERVICE != getRsItemVersion(rstype)) || (RS_SERVICE_TYPE_TURTLE != getRsItemService(rstype))) + { +#ifdef SERVER_DEBUG + std::cerr << " Wrong type !!" << std::endl ; +#endif + return NULL; /* wrong type */ + } +#endif + + switch(getRsItemSubType(rstype)) + { + case RS_TURTLE_SUBTYPE_FILE_REQUEST : return new RsTurtleFileRequestItem(data,size) ; + case RS_TURTLE_SUBTYPE_FILE_DATA : return new RsTurtleFileDataItem(data,size) ; + case RS_TURTLE_SUBTYPE_FILE_MAP_REQUEST : return new RsTurtleFileMapRequestItem(data,size) ; + case RS_TURTLE_SUBTYPE_FILE_MAP : return new RsTurtleFileMapItem(data,size) ; + case RS_TURTLE_SUBTYPE_FILE_CRC_REQUEST : return new RsTurtleFileCrcRequestItem(data,size) ; + case RS_TURTLE_SUBTYPE_FILE_CRC : return new RsTurtleFileCrcItem(data,size) ; + case RS_TURTLE_SUBTYPE_CHUNK_CRC_REQUEST : return new RsTurtleChunkCrcRequestItem(data,size) ; + case RS_TURTLE_SUBTYPE_CHUNK_CRC : return new RsTurtleChunkCrcItem(data,size) ; + + default: + return NULL ; + } +} + +void ftServer::addVirtualPeer(const TurtleFileHash& hash,const TurtleVirtualPeerId& virtual_peer_id,RsTurtleGenericTunnelItem::Direction dir) +{ + if(dir == RsTurtleGenericTunnelItem::DIRECTION_SERVER) + mFtController->addFileSource(hash,virtual_peer_id) ; +} +void ftServer::removeVirtualPeer(const TurtleFileHash& hash,const TurtleVirtualPeerId& virtual_peer_id) +{ + mFtController->removeFileSource(hash,virtual_peer_id) ; +} + +bool ftServer::handleTunnelRequest(const std::string& hash,const std::string& peer_id) +{ + FileInfo info ; + bool res = FileDetails(hash, RS_FILE_HINTS_NETWORK_WIDE | RS_FILE_HINTS_LOCAL | RS_FILE_HINTS_EXTRA | RS_FILE_HINTS_SPEC_ONLY | RS_FILE_HINTS_DOWNLOAD, info); + +#ifdef SERVER_DEBUG + std::cerr << "ftServer: performing local hash search for hash " << hash << std::endl; + + if(res) + { + std::cerr << "Found hash: " << std::endl; + std::cerr << " hash = " << hash << std::endl; + std::cerr << " peer = " << peer_id << std::endl; + std::cerr << " flags = " << info.storage_permission_flags << std::endl; + std::cerr << " local = " << rsFiles->FileDetails(hash, RS_FILE_HINTS_NETWORK_WIDE | RS_FILE_HINTS_LOCAL | RS_FILE_HINTS_EXTRA | RS_FILE_HINTS_SPEC_ONLY | RS_FILE_HINTS_DOWNLOAD, info) << std::endl; + std::cerr << " groups= " ; for(std::list::const_iterator it(info.parent_groups.begin());it!=info.parent_groups.end();++it) std::cerr << (*it) << ", " ; std::cerr << std::endl; + std::cerr << " clear = " << rsPeers->computePeerPermissionFlags(peer_id,info.storage_permission_flags,info.parent_groups) << std::endl; + } +#endif + + // The call to computeHashPeerClearance() return a combination of RS_FILE_HINTS_NETWORK_WIDE and RS_FILE_HINTS_BROWSABLE + // This is an additional computation cost, but the way it's written here, it's only called when res is true. + // + res = res && (RS_FILE_HINTS_NETWORK_WIDE & rsPeers->computePeerPermissionFlags(peer_id,info.storage_permission_flags,info.parent_groups)) ; + + return res ; +} + /***************************************************************/ /******************* ExtraFileList Access **********************/ /***************************************************************/ @@ -809,7 +885,14 @@ bool ftServer::loadConfigMap(std::map &/*configMap*/) bool ftServer::sendDataRequest(const std::string& peerId, const std::string& hash, uint64_t size, uint64_t offset, uint32_t chunksize) { if(mTurtleRouter->isTurtlePeer(peerId)) - mTurtleRouter->sendDataRequest(peerId,hash,size,offset,chunksize) ; + { + RsTurtleFileRequestItem *item = new RsTurtleFileRequestItem ; + + item->chunk_offset = offset ; + item->chunk_size = chunksize ; + + mTurtleRouter->sendTurtleData(peerId,item) ; + } else { /* create a packet */ @@ -836,7 +919,10 @@ bool ftServer::sendDataRequest(const std::string& peerId, const std::string& has bool ftServer::sendChunkMapRequest(const std::string& peerId,const std::string& hash,bool is_client) { if(mTurtleRouter->isTurtlePeer(peerId)) - mTurtleRouter->sendChunkMapRequest(peerId,hash,is_client) ; + { + RsTurtleFileMapRequestItem *item = new RsTurtleFileMapRequestItem ; + mTurtleRouter->sendTurtleData(peerId,item) ; + } else { /* create a packet */ @@ -859,7 +945,11 @@ bool ftServer::sendChunkMapRequest(const std::string& peerId,const std::string& bool ftServer::sendChunkMap(const std::string& peerId,const std::string& hash,const CompressedChunkMap& map,bool is_client) { if(mTurtleRouter->isTurtlePeer(peerId)) - mTurtleRouter->sendChunkMap(peerId,hash,map,is_client) ; + { + RsTurtleFileMapItem *item = new RsTurtleFileMapItem ; + item->compressed_map = map ; + mTurtleRouter->sendTurtleData(peerId,item) ; + } else { /* create a packet */ @@ -882,7 +972,11 @@ bool ftServer::sendChunkMap(const std::string& peerId,const std::string& hash,co bool ftServer::sendCRC32MapRequest(const std::string& peerId,const std::string& hash) { if(mTurtleRouter->isTurtlePeer(peerId)) - mTurtleRouter->sendCRC32MapRequest(peerId,hash) ; + { + RsTurtleFileCrcRequestItem *item = new RsTurtleFileCrcRequestItem; + + mTurtleRouter->sendTurtleData(peerId,item) ; + } else { /* create a packet */ @@ -903,7 +997,12 @@ bool ftServer::sendCRC32MapRequest(const std::string& peerId,const std::string& bool ftServer::sendSingleChunkCRCRequest(const std::string& peerId,const std::string& hash,uint32_t chunk_number) { if(mTurtleRouter->isTurtlePeer(peerId)) - mTurtleRouter->sendSingleChunkCRCRequest(peerId,hash,chunk_number) ; + { + RsTurtleChunkCrcRequestItem *item = new RsTurtleChunkCrcRequestItem; + item->chunk_number = chunk_number ; + + mTurtleRouter->sendTurtleData(peerId,item) ; + } else { /* create a packet */ @@ -926,7 +1025,12 @@ bool ftServer::sendSingleChunkCRCRequest(const std::string& peerId,const std::st bool ftServer::sendCRC32Map(const std::string& peerId,const std::string& hash,const CRC32Map& crcmap) { if(mTurtleRouter->isTurtlePeer(peerId)) - mTurtleRouter->sendCRC32Map(peerId,hash,crcmap) ; + { + RsTurtleFileCrcItem *item = new RsTurtleFileCrcItem ; + item->crc_map = crcmap ; + + mTurtleRouter->sendTurtleData(peerId,item) ; + } else { /* create a packet */ @@ -948,7 +1052,13 @@ bool ftServer::sendCRC32Map(const std::string& peerId,const std::string& hash,co bool ftServer::sendSingleChunkCRC(const std::string& peerId,const std::string& hash,uint32_t chunk_number,const Sha1CheckSum& crc) { if(mTurtleRouter->isTurtlePeer(peerId)) - mTurtleRouter->sendSingleChunkCRC(peerId,hash,chunk_number,crc) ; + { + RsTurtleChunkCrcItem *item = new RsTurtleChunkCrcItem; + item->chunk_number = chunk_number ; + item->check_sum = crc ; + + mTurtleRouter->sendTurtleData(peerId,item) ; + } else { /* create a packet */ @@ -1003,7 +1113,23 @@ bool ftServer::sendData(const std::string& peerId, const std::string& hash, uint /******** New Serialiser Type *******/ if(mTurtleRouter->isTurtlePeer(peerId)) - mTurtleRouter->sendFileData(peerId,hash,size,baseoffset+offset,chunk,&(((uint8_t *) data)[offset])) ; + { + RsTurtleFileDataItem *item = new RsTurtleFileDataItem ; + + item->chunk_offset = offset+baseoffset ; + item->chunk_size = chunk; + item->chunk_data = malloc(chunk) ; + + if(item->chunk_data == NULL) + { + std::cerr << "p3turtle: Warning: failed malloc of " << chunk << " bytes for sending data packet." << std::endl ; + delete item; + return false; + } + memcpy(item->chunk_data,&(((uint8_t *) data)[offset]),chunk) ; + + mTurtleRouter->sendTurtleData(peerId,item) ; + } else { RsFileData *rfd = new RsFileData(); @@ -1047,6 +1173,76 @@ bool ftServer::sendData(const std::string& peerId, const std::string& hash, uint return true; } +void ftServer::receiveTurtleData(RsTurtleGenericTunnelItem *i, + const std::string& hash, + const std::string& virtual_peer_id, + RsTurtleGenericTunnelItem::Direction direction) +{ + switch(i->PacketSubType()) + { + case RS_TURTLE_SUBTYPE_FILE_REQUEST: + { + RsTurtleFileRequestItem *item = dynamic_cast(i) ; + getMultiplexer()->recvDataRequest(virtual_peer_id,hash,0,item->chunk_offset,item->chunk_size) ; + } + break ; + + case RS_TURTLE_SUBTYPE_FILE_DATA : + { + RsTurtleFileDataItem *item = dynamic_cast(i) ; + 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 + // down _ft_server->getMultiplexer()->recvData()...in ftTransferModule::recvFileData + + } + break ; + + case RS_TURTLE_SUBTYPE_FILE_MAP : + { + RsTurtleFileMapItem *item = dynamic_cast(i) ; + getMultiplexer()->recvChunkMap(virtual_peer_id,hash,item->compressed_map,direction == RsTurtleGenericTunnelItem::DIRECTION_CLIENT) ; + } + break ; + + case RS_TURTLE_SUBTYPE_FILE_MAP_REQUEST: + { + RsTurtleFileMapRequestItem *item = dynamic_cast(i) ; + getMultiplexer()->recvChunkMapRequest(virtual_peer_id,hash,direction == RsTurtleGenericTunnelItem::DIRECTION_CLIENT) ; + } + break ; + + case RS_TURTLE_SUBTYPE_FILE_CRC : + { + RsTurtleFileCrcItem *item = dynamic_cast(i) ; + getMultiplexer()->recvCRC32Map(virtual_peer_id,hash,item->crc_map) ; + } + break ; + + case RS_TURTLE_SUBTYPE_FILE_CRC_REQUEST: + { + getMultiplexer()->recvCRC32MapRequest(virtual_peer_id,hash) ; + } + break ; + + case RS_TURTLE_SUBTYPE_CHUNK_CRC : + { + RsTurtleChunkCrcItem *item = dynamic_cast(i) ; + getMultiplexer()->recvSingleChunkCRC(virtual_peer_id,hash,item->chunk_number,item->check_sum) ; + } + break ; + + case RS_TURTLE_SUBTYPE_CHUNK_CRC_REQUEST: + { + RsTurtleChunkCrcRequestItem *item = dynamic_cast(i) ; + getMultiplexer()->recvSingleChunkCRCRequest(virtual_peer_id,hash,item->chunk_number) ; + } + break ; + default: + std::cerr << "WARNING: Unknown packet type received: sub_id=" << reinterpret_cast(i->PacketSubType()) << ". Is somebody trying to poison you ?" << std::endl ; + } +} + /* NB: The rsCore lock must be activated before calling this. * This Lock should be moved lower into the system... diff --git a/libretroshare/src/ft/ftserver.h b/libretroshare/src/ft/ftserver.h index c105bb2c7..32a881b27 100644 --- a/libretroshare/src/ft/ftserver.h +++ b/libretroshare/src/ft/ftserver.h @@ -44,6 +44,7 @@ #include #include "ft/ftdata.h" +#include "turtle/turtleclientservice.h" #include "retroshare/rsfiles.h" //#include "dbase/cachestrapper.h" @@ -72,142 +73,151 @@ class ftDwlQueue; class p3PeerMgr; class p3LinkMgr; -class ftServer: public RsFiles, public ftDataSend, public RsThread +class ftServer: public RsFiles, public ftDataSend, public RsTurtleClientService, public RsThread { public: - /***************************************************************/ - /******************** Setup ************************************/ - /***************************************************************/ + /***************************************************************/ + /******************** Setup ************************************/ + /***************************************************************/ - ftServer(p3PeerMgr *peerMgr, p3LinkMgr *linkMgr); + ftServer(p3PeerMgr *peerMgr, p3LinkMgr *linkMgr); - /* Assign important variables */ -void setConfigDirectory(std::string path); + /* Assign important variables */ + void setConfigDirectory(std::string path); -void setP3Interface(P3Interface *pqi); + void setP3Interface(P3Interface *pqi); - /* add Config Items (Extra, Controller) */ -void addConfigComponents(p3ConfigMgr *mgr); + /* add Config Items (Extra, Controller) */ + void addConfigComponents(p3ConfigMgr *mgr); -virtual CacheStrapper *getCacheStrapper(); -virtual CacheTransfer *getCacheTransfer(); + virtual CacheStrapper *getCacheStrapper(); + virtual CacheTransfer *getCacheTransfer(); -std::string OwnId(); + std::string OwnId(); - /* Final Setup (once everything is assigned) */ -//void SetupFtServer(); -void SetupFtServer(NotifyBase *cb); -void connectToTurtleRouter(p3turtle *p) ; + /* Final Setup (once everything is assigned) */ + //void SetupFtServer(); + void SetupFtServer(NotifyBase *cb); + void connectToTurtleRouter(p3turtle *p) ; -void StartupThreads(); -void StopThreads(); + void StartupThreads(); + void StopThreads(); - /* own thread */ -virtual void run(); + /* own thread */ + virtual void run(); -// Checks that the given hash is well formed. Used to chase -// string bugs. -static bool checkHash(const std::string& hash,std::string& error_string) ; + // Checks that the given hash is well formed. Used to chase + // string bugs. + static bool checkHash(const std::string& hash,std::string& error_string) ; - /***************************************************************/ - /*************** Control Interface *****************************/ - /************** (Implements RsFiles) ***************************/ - /***************************************************************/ + // Implements RsTurtleClientService + // + virtual bool handleTunnelRequest(const std::string& hash,const std::string& peer_id) ; + virtual void receiveTurtleData(RsTurtleGenericTunnelItem *item,const std::string& hash,const std::string& virtual_peer_id,RsTurtleGenericTunnelItem::Direction direction) ; + virtual RsTurtleGenericTunnelItem *deserialiseItem(void *data,uint32_t size) const ; -// member access + void addVirtualPeer(const TurtleFileHash&, const TurtleVirtualPeerId&,RsTurtleGenericTunnelItem::Direction dir) ; + void removeVirtualPeer(const TurtleFileHash&, const TurtleVirtualPeerId&) ; -ftDataMultiplex *getMultiplexer() const { return mFtDataplex ; } -ftController *getController() const { return mFtController ; } + /***************************************************************/ + /*************** Control Interface *****************************/ + /************** (Implements RsFiles) ***************************/ + /***************************************************************/ -/*** - * Control of Downloads - ***/ -virtual bool alreadyHaveFile(const std::string& hash, FileInfo &info); -virtual bool FileRequest(const std::string& fname, const std::string& hash, uint64_t size, const std::string& dest, TransferRequestFlags flags, const std::list& srcIds); -virtual bool FileCancel(const std::string& hash); -virtual bool FileControl(const std::string& hash, uint32_t flags); -virtual bool FileClearCompleted(); -virtual bool setDestinationDirectory(const std::string& hash,const std::string& new_path) ; -virtual bool setDestinationName(const std::string& hash,const std::string& new_name) ; -virtual bool setChunkStrategy(const std::string& hash,FileChunksInfo::ChunkStrategy s) ; -virtual void setDefaultChunkStrategy(FileChunksInfo::ChunkStrategy) ; -virtual FileChunksInfo::ChunkStrategy defaultChunkStrategy() ; -virtual uint32_t freeDiskSpaceLimit() const ; -virtual void setFreeDiskSpaceLimit(uint32_t size_in_mb) ; + // member access + + ftDataMultiplex *getMultiplexer() const { return mFtDataplex ; } + ftController *getController() const { return mFtController ; } + + /*** + * Control of Downloads + ***/ + virtual bool alreadyHaveFile(const std::string& hash, FileInfo &info); + virtual bool FileRequest(const std::string& fname, const std::string& hash, uint64_t size, const std::string& dest, TransferRequestFlags flags, const std::list& srcIds); + virtual bool FileCancel(const std::string& hash); + virtual bool FileControl(const std::string& hash, uint32_t flags); + virtual bool FileClearCompleted(); + virtual bool setDestinationDirectory(const std::string& hash,const std::string& new_path) ; + virtual bool setDestinationName(const std::string& hash,const std::string& new_name) ; + virtual bool setChunkStrategy(const std::string& hash,FileChunksInfo::ChunkStrategy s) ; + virtual void setDefaultChunkStrategy(FileChunksInfo::ChunkStrategy) ; + virtual FileChunksInfo::ChunkStrategy defaultChunkStrategy() ; + virtual uint32_t freeDiskSpaceLimit() const ; + virtual void setFreeDiskSpaceLimit(uint32_t size_in_mb) ; -/*** - * Control of Downloads Priority. - ***/ -virtual uint32_t getMinPrioritizedTransfers() ; -virtual void setMinPrioritizedTransfers(uint32_t s) ; -virtual uint32_t getQueueSize() ; -virtual void setQueueSize(uint32_t s) ; -virtual bool changeQueuePosition(const std::string hash, QueueMove queue_mv); -virtual bool changeDownloadSpeed(const std::string hash, int speed); -virtual bool getDownloadSpeed(const std::string hash, int & speed); -virtual bool clearDownload(const std::string hash); -//virtual void getDwlDetails(std::list & details); + /*** + * Control of Downloads Priority. + ***/ + virtual uint32_t getMinPrioritizedTransfers() ; + virtual void setMinPrioritizedTransfers(uint32_t s) ; + virtual uint32_t getQueueSize() ; + virtual void setQueueSize(uint32_t s) ; + virtual bool changeQueuePosition(const std::string hash, QueueMove queue_mv); + virtual bool changeDownloadSpeed(const std::string hash, int speed); + virtual bool getDownloadSpeed(const std::string hash, int & speed); + virtual bool clearDownload(const std::string hash); + //virtual void getDwlDetails(std::list & details); -/*** - * Download/Upload Details - ***/ -virtual bool FileDownloads(std::list &hashs); -virtual bool FileUploads(std::list &hashs); -virtual bool FileDetails(const std::string &hash, FileSearchFlags hintflags, FileInfo &info); -virtual bool FileDownloadChunksDetails(const std::string& hash,FileChunksInfo& info) ; -virtual bool FileUploadChunksDetails(const std::string& hash,const std::string& peer_id,CompressedChunkMap& map) ; + /*** + * Download/Upload Details + ***/ + virtual bool FileDownloads(std::list &hashs); + virtual bool FileUploads(std::list &hashs); + virtual bool FileDetails(const std::string &hash, FileSearchFlags hintflags, FileInfo &info); + virtual bool FileDownloadChunksDetails(const std::string& hash,FileChunksInfo& info) ; + virtual bool FileUploadChunksDetails(const std::string& hash,const std::string& peer_id,CompressedChunkMap& map) ; -/*** - * Extra List Access - ***/ -virtual bool ExtraFileAdd(std::string fname, std::string hash, uint64_t size, uint32_t period, TransferRequestFlags flags); -virtual bool ExtraFileRemove(std::string hash, TransferRequestFlags flags); -virtual bool ExtraFileHash(std::string localpath, uint32_t period, TransferRequestFlags flags); -virtual bool ExtraFileStatus(std::string localpath, FileInfo &info); -virtual bool ExtraFileMove(std::string fname, std::string hash, uint64_t size, std::string destpath); + /*** + * Extra List Access + ***/ + virtual bool ExtraFileAdd(std::string fname, std::string hash, uint64_t size, uint32_t period, TransferRequestFlags flags); + virtual bool ExtraFileRemove(std::string hash, TransferRequestFlags flags); + virtual bool ExtraFileHash(std::string localpath, uint32_t period, TransferRequestFlags flags); + virtual bool ExtraFileStatus(std::string localpath, FileInfo &info); + virtual bool ExtraFileMove(std::string fname, std::string hash, uint64_t size, std::string destpath); -/*** - * Directory Listing / Search Interface - ***/ -virtual int RequestDirDetails(const std::string& uid, const std::string& path, DirDetails &details); -virtual int RequestDirDetails(void *ref, DirDetails &details, FileSearchFlags flags); -virtual uint32_t getType(void *ref,FileSearchFlags flags) ; + /*** + * Directory Listing / Search Interface + ***/ + virtual int RequestDirDetails(const std::string& uid, const std::string& path, DirDetails &details); + virtual int RequestDirDetails(void *ref, DirDetails &details, FileSearchFlags flags); + virtual uint32_t getType(void *ref,FileSearchFlags flags) ; -virtual int SearchKeywords(std::list keywords, std::list &results,FileSearchFlags flags); -virtual int SearchKeywords(std::list keywords, std::list &results,FileSearchFlags flags,const std::string& peer_id); -virtual int SearchBoolExp(Expression * exp, std::list &results,FileSearchFlags flags); -virtual int SearchBoolExp(Expression * exp, std::list &results,FileSearchFlags flags,const std::string& peer_id); + virtual int SearchKeywords(std::list keywords, std::list &results,FileSearchFlags flags); + virtual int SearchKeywords(std::list keywords, std::list &results,FileSearchFlags flags,const std::string& peer_id); + virtual int SearchBoolExp(Expression * exp, std::list &results,FileSearchFlags flags); + virtual int SearchBoolExp(Expression * exp, std::list &results,FileSearchFlags flags,const std::string& peer_id); -/*** - * Utility Functions - ***/ -virtual bool ConvertSharedFilePath(std::string path, std::string &fullpath); -virtual void ForceDirectoryCheck(); -virtual void updateSinceGroupPermissionsChanged() ; -virtual bool InDirectoryCheck(); -virtual bool CopyFile(const std::string& source, const std::string& dest); + /*** + * Utility Functions + ***/ + virtual bool ConvertSharedFilePath(std::string path, std::string &fullpath); + virtual void ForceDirectoryCheck(); + virtual void updateSinceGroupPermissionsChanged() ; + virtual bool InDirectoryCheck(); + virtual bool CopyFile(const std::string& source, const std::string& dest); -/*** - * Directory Handling - ***/ -virtual void setDownloadDirectory(std::string path); -virtual void setPartialsDirectory(std::string path); -virtual std::string getDownloadDirectory(); -virtual std::string getPartialsDirectory(); + /*** + * Directory Handling + ***/ + virtual void setDownloadDirectory(std::string path); + virtual void setPartialsDirectory(std::string path); + virtual std::string getDownloadDirectory(); + virtual std::string getPartialsDirectory(); -virtual bool getSharedDirectories(std::list &dirs); -virtual bool setSharedDirectories(std::list &dirs); -virtual bool addSharedDirectory(const SharedDirInfo& dir); -virtual bool updateShareFlags(const SharedDirInfo& dir); // updates the flags. The directory should already exist ! -virtual bool removeSharedDirectory(std::string dir); + virtual bool getSharedDirectories(std::list &dirs); + virtual bool setSharedDirectories(std::list &dirs); + virtual bool addSharedDirectory(const SharedDirInfo& dir); + virtual bool updateShareFlags(const SharedDirInfo& dir); // updates the flags. The directory should already exist ! + virtual bool removeSharedDirectory(std::string dir); -virtual bool getShareDownloadDirectory(); -virtual bool shareDownloadDirectory(bool share); + virtual bool getShareDownloadDirectory(); + virtual bool shareDownloadDirectory(bool share); virtual void setRememberHashFilesDuration(uint32_t days) ; virtual uint32_t rememberHashFilesDuration() const ; @@ -217,84 +227,84 @@ virtual bool shareDownloadDirectory(bool share); virtual void setWatchPeriod(int minutes) ; virtual int watchPeriod() const ; - /***************************************************************/ - /*************** Control Interface *****************************/ - /***************************************************************/ + /***************************************************************/ + /*************** Control Interface *****************************/ + /***************************************************************/ - /***************************************************************/ - /*************** Data Transfer Interface ***********************/ - /***************************************************************/ -public: -virtual bool sendData(const std::string& peerId, const std::string& hash, uint64_t size, uint64_t offset, uint32_t chunksize, void *data); -virtual bool sendDataRequest(const std::string& peerId, const std::string& hash, uint64_t size, uint64_t offset, uint32_t chunksize); -virtual bool sendChunkMapRequest(const std::string& peer_id,const std::string& hash,bool is_client) ; -virtual bool sendChunkMap(const std::string& peer_id,const std::string& hash,const CompressedChunkMap& cmap,bool is_client) ; -virtual bool sendCRC32MapRequest(const std::string&, const std::string&) ; -virtual bool sendCRC32Map(const std::string&, const std::string&, const CRC32Map&) ; -virtual bool sendSingleChunkCRCRequest(const std::string& peer_id,const std::string& hash,uint32_t chunk_number) ; -virtual bool sendSingleChunkCRC(const std::string& peer_id,const std::string& hash,uint32_t chunk_number,const Sha1CheckSum& crc) ; + /***************************************************************/ + /*************** Data Transfer Interface ***********************/ + /***************************************************************/ + public: + virtual bool sendData(const std::string& peerId, const std::string& hash, uint64_t size, uint64_t offset, uint32_t chunksize, void *data); + virtual bool sendDataRequest(const std::string& peerId, const std::string& hash, uint64_t size, uint64_t offset, uint32_t chunksize); + virtual bool sendChunkMapRequest(const std::string& peer_id,const std::string& hash,bool is_client) ; + virtual bool sendChunkMap(const std::string& peer_id,const std::string& hash,const CompressedChunkMap& cmap,bool is_client) ; + virtual bool sendCRC32MapRequest(const std::string&, const std::string&) ; + virtual bool sendCRC32Map(const std::string&, const std::string&, const CRC32Map&) ; + virtual bool sendSingleChunkCRCRequest(const std::string& peer_id,const std::string& hash,uint32_t chunk_number) ; + virtual bool sendSingleChunkCRC(const std::string& peer_id,const std::string& hash,uint32_t chunk_number,const Sha1CheckSum& crc) ; - /*************** Internal Transfer Fns *************************/ -virtual int tick(); + /*************** Internal Transfer Fns *************************/ + virtual int tick(); - /* Configuration */ -bool addConfiguration(p3ConfigMgr *cfgmgr); -bool ResumeTransfers(); + /* Configuration */ + bool addConfiguration(p3ConfigMgr *cfgmgr); + bool ResumeTransfers(); -private: -bool handleInputQueues(); -bool handleCacheData(); -bool handleFileData(); + private: + bool handleInputQueues(); + bool handleCacheData(); + bool handleFileData(); - /******************* p3 Config Overload ************************/ + /******************* p3 Config Overload ************************/ protected: - /* Key Functions to be overloaded for Full Configuration */ -virtual RsSerialiser *setupSerialiser(); -virtual bool saveList(bool &cleanup, std::list&); -virtual bool loadList(std::list& load); + /* Key Functions to be overloaded for Full Configuration */ + virtual RsSerialiser *setupSerialiser(); + virtual bool saveList(bool &cleanup, std::list&); + virtual bool loadList(std::list& load); private: -bool loadConfigMap(std::map &configMap); - /******************* p3 Config Overload ************************/ + bool loadConfigMap(std::map &configMap); + /******************* p3 Config Overload ************************/ -/*************************** p3 Config Overload ********************/ + /*************************** p3 Config Overload ********************/ private: - /**** INTERNAL FUNCTIONS ***/ -//virtual int reScanDirs(); -//virtual int check_dBUpdate(); + /**** INTERNAL FUNCTIONS ***/ + //virtual int reScanDirs(); + //virtual int check_dBUpdate(); private: - /* no need for Mutex protection - - * as each component is protected independently. - */ + /* no need for Mutex protection - + * as each component is protected independently. + */ - P3Interface *mP3iface; /* XXX THIS NEEDS PROTECTION */ + P3Interface *mP3iface; /* XXX THIS NEEDS PROTECTION */ - p3PeerMgr *mPeerMgr; - p3LinkMgr *mLinkMgr; - - ftCacheStrapper *mCacheStrapper; - ftFiStore *mFiStore; - ftFiMonitor *mFiMon; + p3PeerMgr *mPeerMgr; + p3LinkMgr *mLinkMgr; - ftController *mFtController; - ftExtraList *mFtExtra; + ftCacheStrapper *mCacheStrapper; + ftFiStore *mFiStore; + ftFiMonitor *mFiMon; - ftDataMultiplex *mFtDataplex; - p3turtle *mTurtleRouter ; + ftController *mFtController; + ftExtraList *mFtExtra; + + ftDataMultiplex *mFtDataplex; + p3turtle *mTurtleRouter ; - ftFileSearch *mFtSearch; + ftFileSearch *mFtSearch; - ftDwlQueue *mFtDwlQueue; + ftDwlQueue *mFtDwlQueue; - RsMutex srvMutex; - std::string mConfigPath; - std::string mDownloadPath; - std::string mPartialsPath; + RsMutex srvMutex; + std::string mConfigPath; + std::string mDownloadPath; + std::string mPartialsPath; }; diff --git a/libretroshare/src/ft/ftturtlefiletransferitem.cc b/libretroshare/src/ft/ftturtlefiletransferitem.cc new file mode 100644 index 000000000..1b0be2b2d --- /dev/null +++ b/libretroshare/src/ft/ftturtlefiletransferitem.cc @@ -0,0 +1,739 @@ +/* + * libretroshare/src/services: ftturtlefiletransferitem.cc + * + * Services for RetroShare. + * + * Copyright 2013 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 "csoler@users.sourceforge.net". + * + */ + +#include +#include + +#include +#include + +uint32_t RsTurtleFileRequestItem::serial_size() +{ + uint32_t s = 0 ; + + s += 8 ; // header + s += 4 ; // tunnel id + s += 8 ; // file offset + s += 4 ; // chunk size + + return s ; +} + +uint32_t RsTurtleFileDataItem::serial_size() +{ + uint32_t s = 0 ; + + s += 8 ; // header + s += 4 ; // tunnel id + s += 8 ; // file offset + s += 4 ; // chunk size + s += chunk_size ; // actual data size. + + return s ; +} + +uint32_t RsTurtleFileMapRequestItem::serial_size() +{ + uint32_t s = 0 ; + + s += 8 ; // header + s += 4 ; // tunnel id + s += 4 ; // direction + + return s ; +} + +uint32_t RsTurtleFileMapItem::serial_size() +{ + uint32_t s = 0 ; + + s += 8 ; // header + s += 4 ; // tunnel id + s += 4 ; // direction + s += 4 ; // compressed_map.size() + + s += 4 * compressed_map._map.size() ; + + return s ; +} + +uint32_t RsTurtleFileCrcRequestItem::serial_size() +{ + uint32_t s = 0 ; + + s += 8 ; // header + s += 4 ; // tunnel id + + return s ; +} +uint32_t RsTurtleChunkCrcItem::serial_size() +{ + uint32_t s = 0 ; + + s += 8 ; // header + s += 4 ; // tunnel id + s += 4 ; // chunk number + s += 20 ; // check_sum + + return s ; +} +uint32_t RsTurtleChunkCrcRequestItem::serial_size() +{ + uint32_t s = 0 ; + + s += 8 ; // header + s += 4 ; // tunnel id + s += 4 ; // chunk number + + return s ; +} +uint32_t RsTurtleFileCrcItem::serial_size() +{ + uint32_t s = 0 ; + + s += 8 ; // header + s += 4 ; // tunnel id + + s += 4 ; // size of _map + s += 4 ; // size of _crcs + + s += 4 * crc_map._crcs.size() ; + s += 4 * crc_map._ccmap._map.size() ; + + return s ; +} +bool RsTurtleFileMapRequestItem::serialize(void *data,uint32_t& pktsize) +{ + uint32_t tlvsize = serial_size(); + uint32_t offset = 0; + + if (pktsize < tlvsize) + return false; /* not enough space */ + + pktsize = tlvsize; + + bool ok = true; + + ok &= setRsItemHeader(data,tlvsize,PacketId(), tlvsize); + + /* skip the header */ + offset += 8; + + /* add mandatory parts first */ + + ok &= setRawUInt32(data, tlvsize, &offset, tunnel_id); + ok &= setRawUInt32(data, tlvsize, &offset, direction); + + if (offset != tlvsize) + { + ok = false; +#ifdef RSSERIAL_DEBUG + std::cerr << "RsFileConfigSerialiser::serialiseTransfer() Size Error! " << std::endl; +#endif + } + + return ok; +} + +bool RsTurtleFileMapItem::serialize(void *data,uint32_t& pktsize) +{ + uint32_t tlvsize = serial_size(); + uint32_t offset = 0; + + if (pktsize < tlvsize) + return false; /* not enough space */ + + pktsize = tlvsize; + + bool ok = true; + + ok &= setRsItemHeader(data,tlvsize,PacketId(), tlvsize); + + /* skip the header */ + offset += 8; + + /* add mandatory parts first */ + + ok &= setRawUInt32(data, tlvsize, &offset, tunnel_id); + ok &= setRawUInt32(data, tlvsize, &offset, direction); + ok &= setRawUInt32(data, tlvsize, &offset, compressed_map._map.size()); + + for(uint32_t i=0;i +#include + +/***********************************************************************************/ +/* Turtle File Transfer item classes */ +/***********************************************************************************/ + +class RsTurtleFileRequestItem: public RsTurtleGenericTunnelItem +{ + public: + RsTurtleFileRequestItem() : RsTurtleGenericTunnelItem(RS_TURTLE_SUBTYPE_FILE_REQUEST) { setPriorityLevel(QOS_PRIORITY_RS_TURTLE_FILE_REQUEST);} + RsTurtleFileRequestItem(void *data,uint32_t size) ; // deserialization + + virtual bool shouldStampTunnel() const { return false ; } + virtual Direction travelingDirection() const { return DIRECTION_SERVER ; } + + uint64_t chunk_offset ; + uint32_t chunk_size ; + + virtual std::ostream& print(std::ostream& o, uint16_t) ; + protected: + virtual bool serialize(void *data,uint32_t& size) ; + virtual uint32_t serial_size() ; +}; + +class RsTurtleFileDataItem: public RsTurtleGenericTunnelItem +{ + public: + RsTurtleFileDataItem() : RsTurtleGenericTunnelItem(RS_TURTLE_SUBTYPE_FILE_DATA) { setPriorityLevel(QOS_PRIORITY_RS_TURTLE_FILE_DATA) ;} + ~RsTurtleFileDataItem() ; + RsTurtleFileDataItem(void *data,uint32_t size) ; // deserialization + + virtual bool shouldStampTunnel() const { return true ; } + virtual Direction travelingDirection() const { return DIRECTION_CLIENT ; } + + uint64_t chunk_offset ; // offset in the file + uint32_t chunk_size ; // size of the file chunk + void *chunk_data ; // actual data. + + virtual std::ostream& print(std::ostream& o, uint16_t) ; + + virtual bool serialize(void *data,uint32_t& size) ; + virtual uint32_t serial_size() ; +}; + +class RsTurtleFileMapRequestItem: public RsTurtleGenericTunnelItem +{ + public: + RsTurtleFileMapRequestItem() : RsTurtleGenericTunnelItem(RS_TURTLE_SUBTYPE_FILE_MAP_REQUEST) { setPriorityLevel(QOS_PRIORITY_RS_TURTLE_FILE_MAP_REQUEST) ;} + RsTurtleFileMapRequestItem(void *data,uint32_t size) ; // deserialization + + virtual bool shouldStampTunnel() const { return false ; } + + virtual std::ostream& print(std::ostream& o, uint16_t) ; + + virtual bool serialize(void *data,uint32_t& size) ; + virtual uint32_t serial_size() ; +}; + +class RsTurtleFileMapItem: public RsTurtleGenericTunnelItem +{ + public: + RsTurtleFileMapItem() : RsTurtleGenericTunnelItem(RS_TURTLE_SUBTYPE_FILE_MAP) { setPriorityLevel(QOS_PRIORITY_RS_TURTLE_FILE_MAP) ;} + RsTurtleFileMapItem(void *data,uint32_t size) ; // deserialization + + virtual bool shouldStampTunnel() const { return false ; } + + CompressedChunkMap compressed_map ; // Map info for the file in compressed format. Each *bit* in the array uint's says "I have" or "I don't have" + // by default, we suppose the peer has all the chunks. This info will thus be and-ed + // with the default file map for this source. + + virtual std::ostream& print(std::ostream& o, uint16_t) ; + + virtual bool serialize(void *data,uint32_t& size) ; + virtual uint32_t serial_size() ; +}; + +class RsTurtleFileCrcRequestItem: public RsTurtleGenericTunnelItem +{ + public: + RsTurtleFileCrcRequestItem() : RsTurtleGenericTunnelItem(RS_TURTLE_SUBTYPE_FILE_CRC_REQUEST) { setPriorityLevel(QOS_PRIORITY_RS_FILE_CRC_REQUEST);} + RsTurtleFileCrcRequestItem(void *data,uint32_t size) ; // deserialization + + virtual bool shouldStampTunnel() const { return false ; } + virtual Direction travelingDirection() const { return DIRECTION_SERVER ; } + + virtual std::ostream& print(std::ostream& o, uint16_t) ; + + virtual bool serialize(void *data,uint32_t& size) ; + virtual uint32_t serial_size() ; +}; + +class RsTurtleChunkCrcRequestItem: public RsTurtleGenericTunnelItem +{ + public: + RsTurtleChunkCrcRequestItem() : RsTurtleGenericTunnelItem(RS_TURTLE_SUBTYPE_CHUNK_CRC_REQUEST) { setPriorityLevel(QOS_PRIORITY_RS_CHUNK_CRC_REQUEST);} + RsTurtleChunkCrcRequestItem(void *data,uint32_t size) ; // deserialization + + virtual bool shouldStampTunnel() const { return false ; } + virtual Direction travelingDirection() const { return DIRECTION_SERVER ; } + + uint32_t chunk_number ; // id of the chunk to CRC. + + virtual std::ostream& print(std::ostream& o, uint16_t) ; + + virtual bool serialize(void *data,uint32_t& size) ; + virtual uint32_t serial_size() ; +}; + +class RsTurtleFileCrcItem: public RsTurtleGenericTunnelItem +{ + public: + RsTurtleFileCrcItem() : RsTurtleGenericTunnelItem(RS_TURTLE_SUBTYPE_FILE_CRC) { setPriorityLevel(QOS_PRIORITY_RS_FILE_CRC);} + RsTurtleFileCrcItem(void *data,uint32_t size) ; // deserialization + + virtual bool shouldStampTunnel() const { return true ; } + virtual Direction travelingDirection() const { return DIRECTION_CLIENT ; } + + CRC32Map crc_map ;// Map info for the file in compressed format. Each *bit* in the array uint's says "I have" or "I don't have" + // by default, we suppose the peer has all the chunks. This info will thus be and-ed + // with the default file map for this source. + + virtual std::ostream& print(std::ostream& o, uint16_t) ; + virtual bool serialize(void *data,uint32_t& size) ; + virtual uint32_t serial_size() ; +}; + +class RsTurtleChunkCrcItem: public RsTurtleGenericTunnelItem +{ + public: + RsTurtleChunkCrcItem() : RsTurtleGenericTunnelItem(RS_TURTLE_SUBTYPE_CHUNK_CRC) { setPriorityLevel(QOS_PRIORITY_RS_CHUNK_CRC);} + RsTurtleChunkCrcItem(void *data,uint32_t size) ; // deserialization + + virtual bool shouldStampTunnel() const { return true ; } + virtual Direction travelingDirection() const { return DIRECTION_CLIENT ; } + + uint32_t chunk_number ; + Sha1CheckSum check_sum ; + + virtual std::ostream& print(std::ostream& o, uint16_t) ; + virtual bool serialize(void *data,uint32_t& size) ; + virtual uint32_t serial_size() ; +}; diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index 3925754a6..a5b7255b7 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -306,12 +306,14 @@ HEADERS += ft/ftchunkmap.h \ ft/ftfilesearch.h \ ft/ftsearch.h \ ft/ftserver.h \ - ft/fttransfermodule.h + ft/fttransfermodule.h \ + ft/ftturtlefiletransferitem.h HEADERS += pqi/authssl.h \ pqi/authgpg.h \ pgp/pgphandler.h \ pgp/pgpkeyutil.h \ + pgp/rsaes.h \ pgp/rscertificate.h \ pqi/p3cfgmgr.h \ pqi/p3peermgr.h \ @@ -446,6 +448,7 @@ SOURCES += ft/ftchunkmap.cc \ ft/ftfilesearch.cc \ ft/ftserver.cc \ ft/fttransfermodule.cc \ + ft/ftturtlefiletransferitem.cc SOURCES += pqi/authgpg.cc \ pqi/authssl.cc \ @@ -565,6 +568,7 @@ SOURCES += util/folderiterator.cc \ util/rsthreads.cc \ util/rsversion.cc \ util/rswin.cc \ + util/rsaes.cc \ util/rsrandom.cc \ util/rstickevent.cc \ diff --git a/libretroshare/src/pgp/pgphandler.cc b/libretroshare/src/pgp/pgphandler.cc index 6962e30c4..90c779b77 100644 --- a/libretroshare/src/pgp/pgphandler.cc +++ b/libretroshare/src/pgp/pgphandler.cc @@ -943,7 +943,37 @@ bool PGPHandler::addOrMergeKey(ops_keyring_t *keyring,std::maptype != OPS_PTAG_CT_PUBLIC_KEY) +// { +// std::cerr << "PGPHandler::encryptTextToFile(): ERROR: supplied id did not return a public key!" << std::endl; +// return false ; +// } +// +// ops_create_info_t *info; +// ops_memory_t *buf = NULL ; +// ops_setup_memory_write(&info, &buf, 0); +// +// ops_encrypt_stream(info, public_key, NULL, ops_false, ops_true); +// ops_write(text.c_str(), text.length(), info); +// ops_writer_close(info); +// +// outstring = std::string((char *)ops_memory_get_data(buf),ops_memory_get_length(buf)) ; +// ops_create_info_delete(info); +// +// return true ; +// } bool PGPHandler::encryptTextToFile(const PGPIdType& key_id,const std::string& text,const std::string& outfile) { RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. @@ -978,6 +1008,73 @@ bool PGPHandler::encryptTextToFile(const PGPIdType& key_id,const std::string& te return true ; } +bool PGPHandler::encryptDataBin(const PGPIdType& key_id,const void *data, const uint32_t len, unsigned char *encrypted_data, unsigned int *encrypted_data_len) +{ + RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. + + const ops_keydata_t *public_key = locked_getPublicKey(key_id,true) ; + + if(public_key == NULL) + { + std::cerr << "Cannot get public key of id " << key_id.toStdString() << std::endl; + return false ; + } + + if(public_key->type != OPS_PTAG_CT_PUBLIC_KEY) + { + std::cerr << "PGPHandler::encryptTextToFile(): ERROR: supplied id did not return a public key!" << std::endl; + return false ; + } + ops_create_info_t *info; + ops_memory_t *buf = NULL ; + ops_setup_memory_write(&info, &buf, 0); + + ops_encrypt_stream(info, public_key, NULL, ops_false, ops_false); + + ops_write(data,len,info); + ops_writer_close(info); + ops_create_info_delete(info); + + int tlen = ops_memory_get_length(buf) ; + bool res ; + + if( (int)*encrypted_data_len >= tlen) + { + memcpy(encrypted_data,ops_memory_get_data(buf),tlen) ; + *encrypted_data_len = tlen ; + res = true ; + } + else + { + std::cerr << "Not enough room to fit encrypted data. Size given=" << *encrypted_data_len << ", required=" << tlen << std::endl; + res = false ; + } + + ops_memory_release(buf) ; + free(buf) ; + + return res ; +} + +bool PGPHandler::decryptDataBin(const PGPIdType& key_id,const void *encrypted_data, const uint32_t encrypted_len, unsigned char *data, unsigned int *data_len) +{ + int out_length ; + unsigned char *out ; + ops_boolean_t res = ops_decrypt_memory((const unsigned char *)encrypted_data,encrypted_len,&out,&out_length,_secring,ops_false,cb_get_passphrase) ; + + if(*data_len < out_length) + { + std::cerr << "Not enough room to store decrypted data! Please give more."<< std::endl; + return false ; + } + + *data_len = out_length ; + memcpy(data,out,out_length) ; + free(out) ; + + return (bool)res ; +} + bool PGPHandler::decryptTextFromFile(const PGPIdType&,std::string& text,const std::string& inputfile) { RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. @@ -1054,10 +1151,21 @@ bool PGPHandler::SignDataBin(const PGPIdType& id,const void *data, const uint32_ if(!memres) return false ; - uint32_t tlen = std::min(*signlen,(uint32_t)ops_memory_get_length(memres)) ; + bool res ; + uint32_t slen = (uint32_t)ops_memory_get_length(memres); - memcpy(sign,ops_memory_get_data(memres),tlen) ; - *signlen = tlen ; + if(*signlen >= slen) + { + *signlen = slen ; + + memcpy(sign,ops_memory_get_data(memres),*signlen) ; + res = true ; + } + else + { + std::cerr << "(EE) memory chunk is not large enough for signature packet. Requred size: " << slen << " bytes." << std::endl; + res = false ; + } ops_memory_release(memres) ; free(memres) ; @@ -1073,7 +1181,7 @@ bool PGPHandler::SignDataBin(const PGPIdType& id,const void *data, const uint32_ hexdump( (unsigned char *)sign,*signlen) ; std::cerr << std::endl; #endif - return true ; + return res ; } bool PGPHandler::privateSignCertificate(const PGPIdType& ownId,const PGPIdType& id_of_key_to_sign) diff --git a/libretroshare/src/pgp/pgphandler.h b/libretroshare/src/pgp/pgphandler.h index dbe8015d4..716e3b671 100644 --- a/libretroshare/src/pgp/pgphandler.h +++ b/libretroshare/src/pgp/pgphandler.h @@ -94,8 +94,15 @@ class PGPHandler bool VerifySignBin(const void *data, uint32_t data_len, unsigned char *sign, unsigned int sign_len, const PGPFingerprintType& withfingerprint) ; bool privateSignCertificate(const PGPIdType& own_id,const PGPIdType& id_of_key_to_sign) ; + // The client should supply a memory chunk to store the data. The length will be updated to the real length of the data. + // + bool encryptDataBin(const PGPIdType& key_id,const void *data, const uint32_t len, unsigned char *encrypted_data, unsigned int *encrypted_data_len) ; + bool decryptDataBin(const PGPIdType& key_id,const void *data, const uint32_t len, unsigned char *decrypted_data, unsigned int *decrypted_data_len) ; + bool encryptTextToFile(const PGPIdType& key_id,const std::string& text,const std::string& outfile) ; - bool decryptTextFromFile(const PGPIdType& key_id,std::string& text,const std::string& inputfile) ; + bool decryptTextFromFile(const PGPIdType& key_id,std::string& text,const std::string& encrypted_inputfile) ; + //bool encryptTextToString(const PGPIdType& key_id,const std::string& text,std::string& outstring) ; + //bool decryptTextFromString(const PGPIdType& key_id,const std::string& encrypted_text,std::string& outstring) ; bool getKeyFingerprint(const PGPIdType& id,PGPFingerprintType& fp) const ; void setAcceptConnexion(const PGPIdType&,bool) ; diff --git a/libretroshare/src/pqi/authgpg.cc b/libretroshare/src/pqi/authgpg.cc index c98c2053b..86e7a72b8 100644 --- a/libretroshare/src/pqi/authgpg.cc +++ b/libretroshare/src/pqi/authgpg.cc @@ -70,11 +70,21 @@ bool AuthGPG::removeKeysFromPGPKeyring(const std::list& pgp_ids,std return PGPHandler::removeKeysFromPGPKeyring(pids,backup_file,error_code) ; } +// bool AuthGPG::decryptTextFromString(std::string& encrypted_text,std::string& output) +// { +// return PGPHandler::decryptTextFromString(mOwnGpgId,encrypted_text,output) ; +// } + bool AuthGPG::encryptTextToFile(const std::string& text,const std::string& outfile) { return PGPHandler::encryptTextToFile(mOwnGpgId,text,outfile) ; } +// bool AuthGPG::encryptTextToString(const std::string& pgp_id,const std::string& text,std::string& outstr) +// { +// return PGPHandler::encryptTextToString(PGPIdType(pgp_id),text,outstr) ; +// } + std::string pgp_pwd_callback(void * /*hook*/, const char *uid_hint, const char * /*passphrase_info*/, int prev_was_bad) { #define GPG_DEBUG2 @@ -640,6 +650,15 @@ bool AuthGPG::TrustCertificate(const std::string &id, int trustlvl) return privateTrustCertificate(id, trustlvl) ; } +bool AuthGPG::encryptDataBin(const std::string& pgp_id,const void *data, unsigned int datalen, unsigned char *sign, unsigned int *signlen) +{ + return PGPHandler::encryptDataBin(PGPIdType(pgp_id),data,datalen,sign,signlen) ; +} + +bool AuthGPG::decryptDataBin(const void *data, unsigned int datalen, unsigned char *sign, unsigned int *signlen) +{ + return PGPHandler::decryptDataBin(mOwnGpgId,data,datalen,sign,signlen) ; +} bool AuthGPG::SignDataBin(const void *data, unsigned int datalen, unsigned char *sign, unsigned int *signlen) { return DoOwnSignature(data, datalen, sign, signlen); diff --git a/libretroshare/src/pqi/authgpg.h b/libretroshare/src/pqi/authgpg.h index f560fd0e2..9ee944df5 100644 --- a/libretroshare/src/pqi/authgpg.h +++ b/libretroshare/src/pqi/authgpg.h @@ -217,9 +217,15 @@ class AuthGPG: public p3Config, public RsThread, public PGPHandler virtual bool SignDataBin(const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen); virtual bool VerifySignBin(const void*, uint32_t, unsigned char*, unsigned int, const std::string &withfingerprint); + virtual bool encryptDataBin(const std::string& pgp_id,const void *data, const uint32_t len, unsigned char *encr, unsigned int *encrlen); + virtual bool decryptDataBin(const void *data, const uint32_t len, unsigned char *decr, unsigned int *decrlen); + virtual bool decryptTextFromFile( std::string& text,const std::string& filename); virtual bool encryptTextToFile (const std::string& text,const std::string& filename); +// virtual bool decryptTextFromString( std::string& encrypted_text,std::string& clear_string); +// virtual bool encryptTextToString (const std::string& pgp_id,const std::string& clear_text,std::string& encrypted_string); + bool getGPGFilteredList(std::list& list,bool (*filter)(const PGPCertificateInfo&) = NULL) ; //END of PGP public functions diff --git a/libretroshare/src/retroshare/rsmsgs.h b/libretroshare/src/retroshare/rsmsgs.h index a600fe6dc..7922c3e1d 100644 --- a/libretroshare/src/retroshare/rsmsgs.h +++ b/libretroshare/src/retroshare/rsmsgs.h @@ -58,6 +58,7 @@ #define RS_MSG_USER_REQUEST 0x0400 /* user request */ #define RS_MSG_FRIEND_RECOMMENDATION 0x0800 /* friend recommendation */ #define RS_MSG_SYSTEM (RS_MSG_USER_REQUEST | RS_MSG_FRIEND_RECOMMENDATION) +#define RS_MSG_ENCRYPTED 0x1000 /* message is encrypted */ #define RS_CHAT_LOBBY_EVENT_PEER_LEFT 0x01 #define RS_CHAT_LOBBY_EVENT_PEER_STATUS 0x02 @@ -99,6 +100,7 @@ class MessageInfo std::wstring attach_title; std::wstring attach_comment; std::list files; + std::map encryption_keys ; // for concerned ids only the public pgp key id to encrypt the message with. int size; /* total of files */ int count; /* file count */ @@ -144,6 +146,16 @@ public: #define RS_CHAT_PRIVATE 0x0002 #define RS_CHAT_AVATAR_AVAILABLE 0x0004 +#define RS_DISTANT_CHAT_STATUS_UNKNOWN 0x0000 +#define RS_DISTANT_CHAT_STATUS_TUNNEL_DN 0x0001 +#define RS_DISTANT_CHAT_STATUS_TUNNEL_OK 0x0002 +#define RS_DISTANT_CHAT_STATUS_CAN_TALK 0x0003 + +#define RS_DISTANT_CHAT_ERROR_NO_ERROR 0x0000 +#define RS_DISTANT_CHAT_ERROR_DECRYPTION_FAILED 0x0001 +#define RS_DISTANT_CHAT_ERROR_SIGNATURE_MISMATCH 0x0002 +#define RS_DISTANT_CHAT_ERROR_UNKNOWN_KEY 0x0003 + class ChatInfo { public: @@ -195,6 +207,14 @@ class ChatLobbyInfo time_t last_activity ; // last recorded activity. Useful for removing dead lobbies. }; +struct DistantChatInviteInfo +{ + std::string hash ; // hash to contact the invite and refer to it. + std::string encrypted_radix64_string ; // encrypted radix string used to for the chat link + std::string destination_pgp_id ; // pgp is of the destination of the chat link + time_t time_of_validity ; // time when te invite becomes unusable +}; + std::ostream &operator<<(std::ostream &out, const MessageInfo &info); std::ostream &operator<<(std::ostream &out, const ChatInfo &info); @@ -203,6 +223,14 @@ bool operator==(const ChatInfo&, const ChatInfo&); class RsMsgs; extern RsMsgs *rsMsgs; +struct DistantOfflineMessengingInvite +{ + std::string issuer_pgp_id ; + std::string hash ; + time_t time_of_validity ; +}; + + class RsMsgs { public: @@ -211,11 +239,13 @@ class RsMsgs virtual ~RsMsgs() { return; } /****************************************/ - /* Message Items */ +/* Message Items */ +/****************************************/ virtual bool getMessageSummaries(std::list &msgList) = 0; virtual bool getMessage(const std::string &mId, MessageInfo &msg) = 0; virtual void getMessageCount(unsigned int *pnInbox, unsigned int *pnInboxNew, unsigned int *pnOutbox, unsigned int *pnDraftbox, unsigned int *pnSentbox, unsigned int *pnTrashbox) = 0; +virtual bool decryptMessage(const std::string& mId) = 0 ; virtual bool MessageSend(MessageInfo &info) = 0; virtual bool SystemMessage(const std::wstring &title, const std::wstring &message, uint32_t systemFlag) = 0; @@ -241,8 +271,14 @@ virtual bool setMessageTag(const std::string &msgId, uint32_t tagId, bool set) = virtual bool resetMessageStandardTagTypes(MsgTagType& tags) = 0; +/* private distant messages */ + +virtual bool createDistantOfflineMessengingInvite(time_t validity_time_stamp, std::string& hash)=0 ; +virtual bool getDistantOfflineMessengingInvites(std::vector& invites) = 0 ; + +/****************************************/ +/* Chat */ /****************************************/ - /* Chat */ virtual bool sendPublicChat(const std::wstring& msg) = 0; virtual bool sendPrivateChat(const std::string& id, const std::wstring& msg) = 0; virtual int getPublicChatQueueCount() = 0; @@ -265,6 +301,10 @@ virtual void getAvatarData(const std::string& pid,unsigned char *& data,int& siz virtual void setOwnAvatarData(const unsigned char *data,int size) = 0 ; virtual void getOwnAvatarData(unsigned char *& data,int& size) = 0 ; +/****************************************/ +/* Chat lobbies */ +/****************************************/ + virtual bool joinVisibleChatLobby(const ChatLobbyId& lobby_id) = 0 ; virtual bool isLobbyId(const std::string& virtual_peer_id,ChatLobbyId& lobby_id) = 0; virtual bool getVirtualPeerId(const ChatLobbyId& lobby_id,std::string& vpid) = 0; @@ -282,6 +322,13 @@ virtual bool getDefaultNickNameForChatLobby(std::string& nick) = 0 ; virtual ChatLobbyId createChatLobby(const std::string& lobby_name,const std::string& lobby_topic,const std::list& invited_friends,uint32_t lobby_privacy_type) = 0 ; /****************************************/ +/* Distant chat */ +/****************************************/ + +virtual bool createDistantChatInvite(const std::string& pgp_id,time_t time_of_validity,std::string& encrypted_string) = 0 ; +virtual bool getDistantChatInviteList(std::vector& invites) = 0; +virtual bool initiateDistantChatConnexion(const std::string& encrypted_string,std::string& hash,uint32_t& error_code) = 0; +virtual bool getDistantChatStatus(const std::string& hash,uint32_t& status,std::string& pgp_id) = 0; }; diff --git a/libretroshare/src/retroshare/rsturtle.h b/libretroshare/src/retroshare/rsturtle.h index 29d7ccdc3..e66ab7367 100644 --- a/libretroshare/src/retroshare/rsturtle.h +++ b/libretroshare/src/retroshare/rsturtle.h @@ -34,6 +34,7 @@ #include class LinearizedExpression ; +class RsTurtleClientService ; class RsTurtle; extern RsTurtle *rsTurtle ; @@ -83,8 +84,6 @@ class TurtleTrafficStatisticsInfo class RsTurtle { public: - enum FileSharingStrategy { SHARE_ENTIRE_NETWORK, SHARE_FRIENDS_ONLY } ; - RsTurtle() {} virtual ~RsTurtle() {} @@ -103,23 +102,27 @@ class RsTurtle virtual TurtleRequestId turtleSearch(const std::string& match_string) = 0 ; virtual TurtleRequestId turtleSearch(const LinearizedExpression& expr) = 0 ; - // Sets the file sharing strategy. It concerns all local files. It would - // be better to handle this for each file, of course. - - void setFileSharingStrategy(FileSharingStrategy f) { _sharing_strategy = f ; } - // Initiates tunnel handling for the given file hash. tunnels. Launches // an exception if an error occurs during the initialization process. The // turtle router itself does not initiate downloads, it only maintains // tunnels for the given hash. The download should be driven by the file // transfer module by calling ftServer::FileRequest(). // - virtual void monitorFileTunnels(const std::string& name,const std::string& file_hash,uint64_t size) = 0 ; + virtual void monitorTunnels(const std::string& file_hash,RsTurtleClientService *client_service) = 0 ; // Tells the turtle router to stop handling tunnels for the given file hash. Traditionally this should // be called after calling ftServer::fileCancel(). // - virtual void stopMonitoringFileTunnels(const std::string& file_hash) = 0 ; + virtual void stopMonitoringTunnels(const std::string& file_hash) = 0 ; + + /// Adds a client tunnel service. This means that the service will be added + /// to the list of services that might respond to tunnel requests. + /// Example tunnel services include: + /// + /// p3ChatService: tunnels correspond to private distant chatting + /// ftServer : tunnels correspond to file data transfer + /// + virtual void registerTunnelService(RsTurtleClientService *service) = 0; // Get info from the turtle router. I use std strings to hide the internal structs. // @@ -136,8 +139,6 @@ class RsTurtle // Hardcore handles virtual void setMaxTRForwardRate(int max_tr_up_rate) = 0 ; virtual int getMaxTRForwardRate() const = 0 ; - protected: - FileSharingStrategy _sharing_strategy ; }; #endif diff --git a/libretroshare/src/rsserver/p3msgs.cc b/libretroshare/src/rsserver/p3msgs.cc index f95567a4a..1b2d37467 100644 --- a/libretroshare/src/rsserver/p3msgs.cc +++ b/libretroshare/src/rsserver/p3msgs.cc @@ -96,6 +96,20 @@ bool p3Msgs::MessageSend(MessageInfo &info) return mMsgSrv->MessageSend(info); } +bool p3Msgs::decryptMessage(const std::string& mId) +{ + return mMsgSrv->decryptMessage(mId); +} +bool p3Msgs::createDistantOfflineMessengingInvite(time_t ts, std::string& hash) +{ + return mMsgSrv->createDistantOfflineMessengingInvite(ts,hash) ; +} +bool p3Msgs::getDistantOfflineMessengingInvites(std::vector& invites) +{ + return mMsgSrv->getDistantOfflineMessengingInvites(invites); +} + + bool p3Msgs::SystemMessage(const std::wstring &title, const std::wstring &message, uint32_t systemFlag) { return mMsgSrv->SystemMessage(title, message, systemFlag); @@ -330,5 +344,20 @@ void p3Msgs::getPendingChatLobbyInvites(std::list& invites) { mChatSrv->getPendingChatLobbyInvites(invites) ; } - +bool p3Msgs::createDistantChatInvite(const std::string& pgp_id,time_t time_of_validity,std::string& encrypted_string) +{ + return mChatSrv->createDistantChatInvite(pgp_id,time_of_validity,encrypted_string) ; +} +bool p3Msgs::getDistantChatInviteList(std::vector& invites) +{ + return mChatSrv->getDistantChatInviteList(invites) ; +} +bool p3Msgs::initiateDistantChatConnexion(const std::string& encrypted_str,std::string& hash,uint32_t& error_code) +{ + return mChatSrv->initiateDistantChatConnexion(encrypted_str,hash,error_code) ; +} +bool p3Msgs::getDistantChatStatus(const std::string& hash,uint32_t& status,std::string& pgp_id) +{ + return mChatSrv->getDistantChatStatus(hash,status,pgp_id) ; +} diff --git a/libretroshare/src/rsserver/p3msgs.h b/libretroshare/src/rsserver/p3msgs.h index 4da5b74ed..b80757af5 100644 --- a/libretroshare/src/rsserver/p3msgs.h +++ b/libretroshare/src/rsserver/p3msgs.h @@ -58,6 +58,7 @@ class p3Msgs: public RsMsgs virtual void getMessageCount(unsigned int *pnInbox, unsigned int *pnInboxNew, unsigned int *pnOutbox, unsigned int *pnDraftbox, unsigned int *pnSentbox, unsigned int *pnTrashbox); virtual bool MessageSend(MessageInfo &info); + virtual bool decryptMessage(const std::string& mid); virtual bool SystemMessage(const std::wstring &title, const std::wstring &message, uint32_t systemFlag); virtual bool MessageToDraft(MessageInfo &info, const std::string &msgParentId); virtual bool MessageToTrash(const std::string &mid, bool bTrash); @@ -78,6 +79,9 @@ class p3Msgs: public RsMsgs virtual bool resetMessageStandardTagTypes(MsgTagType& tags); + virtual bool createDistantOfflineMessengingInvite(time_t, std::string&) ; + virtual bool getDistantOfflineMessengingInvites(std::vector&); + /*! * gets avatar from peer, image data in jpeg format */ @@ -183,6 +187,11 @@ class p3Msgs: public RsMsgs virtual bool getDefaultNickNameForChatLobby(std::string& nick) ; virtual ChatLobbyId createChatLobby(const std::string& lobby_name,const std::string& lobby_topic,const std::list& invited_friends,uint32_t privacy_type) ; + virtual bool createDistantChatInvite(const std::string& pgp_id,time_t time_of_validity,std::string& encrypted_string) ; + virtual bool getDistantChatInviteList(std::vector& invites); + virtual bool initiateDistantChatConnexion(const std::string& encrypted_string,std::string& hash,uint32_t& error_code) ; + virtual bool getDistantChatStatus(const std::string& hash,uint32_t& status,std::string& pgp_id) ; + private: p3MsgService *mMsgSrv; diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index 0ca118992..f897da3c0 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -2230,10 +2230,13 @@ int RsServer::StartupRetroShare() mConnMgr->setP3tunnel(tn); #endif - p3turtle *tr = new p3turtle(mLinkMgr,ftserver) ; + p3turtle *tr = new p3turtle(mLinkMgr) ; rsTurtle = tr ; pqih -> addService(tr); + ftserver->connectToTurtleRouter(tr) ; + chatSrv->connectToTurtleRouter(tr) ; + msgSrv->connectToTurtleRouter(tr) ; pqih -> addService(ad); pqih -> addService(msgSrv); diff --git a/libretroshare/src/serialiser/itempriorities.h b/libretroshare/src/serialiser/itempriorities.h index cac0eff35..ef8dd2072 100644 --- a/libretroshare/src/serialiser/itempriorities.h +++ b/libretroshare/src/serialiser/itempriorities.h @@ -23,6 +23,10 @@ * */ +#pragma once + +#include + // This file centralises QoS priorities for all transfer RsItems. // const uint8_t QOS_PRIORITY_UNKNOWN = 0 ; @@ -45,6 +49,7 @@ const uint8_t QOS_PRIORITY_RS_TURTLE_CHUNK_CRC = 5 ; const uint8_t QOS_PRIORITY_RS_TURTLE_FILE_MAP = 3 ; const uint8_t QOS_PRIORITY_RS_TURTLE_GENERIC_ITEM = 3 ; const uint8_t QOS_PRIORITY_RS_TURTLE_FORWARD_FILE_DATA= 3 ; +const uint8_t QOS_PRIORITY_RS_TURTLE_GENERIC_DATA = 5 ; // File transfer // diff --git a/libretroshare/src/serialiser/rsmsgitems.cc b/libretroshare/src/serialiser/rsmsgitems.cc index 0338eff9b..c17b44a59 100644 --- a/libretroshare/src/serialiser/rsmsgitems.cc +++ b/libretroshare/src/serialiser/rsmsgitems.cc @@ -188,6 +188,30 @@ std::ostream& RsPrivateChatMsgConfigItem::print(std::ostream &out, uint16_t inde printRsItemEnd(out, "RsPrivateChatMsgConfigItem", indent); return out; } +std::ostream& RsPrivateChatDistantInviteConfigItem::print(std::ostream &out, uint16_t indent) +{ + printRsItemBase(out, "RsPrivateChatDistantInviteConfigItem", indent); + uint16_t int_Indent = indent + 2; + + printIndent(out, int_Indent); + out << "radix string: " << encrypted_radix64_string << std::endl; + + printIndent(out, int_Indent); + out << "hash: " << hash << std::endl; + + printIndent(out, int_Indent); + out << "destination pgp_id: " << destination_pgp_id << std::endl; + + printIndent(out, int_Indent); + out << "time of validity: " << time_of_validity << std::endl; + + printIndent(out, int_Indent); + out << "time of last hit: " << last_hit_time << std::endl; + + printRsItemEnd(out, "RsPrivateChatDistantInviteConfigItem", indent); + return out; +} + std::ostream& RsChatStatusItem::print(std::ostream &out, uint16_t indent) { @@ -195,7 +219,7 @@ std::ostream& RsChatStatusItem::print(std::ostream &out, uint16_t indent) uint16_t int_Indent = indent + 2; printIndent(out, int_Indent); out << "Status string: " << status_string << std::endl; - out << "Flags : " << (void*)flags << std::endl; + out << "Flags : " << std::hex << flags << std::dec << std::endl; printRsItemEnd(out, "RsChatStatusItem", indent); return out; @@ -245,6 +269,7 @@ RsItem *RsChatSerialiser::deserialise(void *data, uint32_t *pktsize) { case RS_PKT_SUBTYPE_DEFAULT: return new RsChatMsgItem(data,*pktsize) ; case RS_PKT_SUBTYPE_PRIVATECHATMSG_CONFIG: return new RsPrivateChatMsgConfigItem(data,*pktsize) ; + case RS_PKT_SUBTYPE_DISTANT_INVITE_CONFIG: return new RsPrivateChatDistantInviteConfigItem(data,*pktsize) ; case RS_PKT_SUBTYPE_CHAT_STATUS: return new RsChatStatusItem(data,*pktsize) ; case RS_PKT_SUBTYPE_CHAT_AVATAR: return new RsChatAvatarItem(data,*pktsize) ; case RS_PKT_SUBTYPE_CHAT_LOBBY_MSG: return new RsChatLobbyMsgItem(data,*pktsize) ; @@ -387,7 +412,18 @@ uint32_t RsPrivateChatMsgConfigItem::serial_size() return s; } +uint32_t RsPrivateChatDistantInviteConfigItem::serial_size() +{ + uint32_t s = 8; /* header */ + s += GetTlvStringSize(hash); + s += GetTlvStringSize(encrypted_radix64_string); + s += GetTlvStringSize(destination_pgp_id); + s += 16; /* aes_key */ + s += 4; /* time_of_validity */ + s += 4; /* last_hit_time */ + return s; +} uint32_t RsChatStatusItem::serial_size() { uint32_t s = 8; /* header */ @@ -780,7 +816,49 @@ bool RsPrivateChatMsgConfigItem::serialise(void *data, uint32_t& pktsize) return ok; } +bool RsPrivateChatDistantInviteConfigItem::serialise(void *data, uint32_t& pktsize) +{ + uint32_t tlvsize = serial_size() ; + uint32_t offset = 0; + if (pktsize < tlvsize) + return false; /* not enough space */ + + pktsize = tlvsize; + + bool ok = true; + + ok &= setRsItemHeader(data, tlvsize, PacketId(), tlvsize); + +#ifdef CHAT_DEBUG + std::cerr << "RsChatSerialiser::serialiseItem() Header: " << ok << std::endl; + std::cerr << "RsChatSerialiser::serialiseItem() Size: " << tlvsize << std::endl; +#endif + + /* skip the header */ + offset += 8; + + /* add mandatory parts first */ + ok &= SetTlvString(data, tlvsize, &offset, TLV_TYPE_STR_KEY, hash); + ok &= SetTlvString(data, tlvsize, &offset, TLV_TYPE_STR_LINK, encrypted_radix64_string); + ok &= SetTlvString(data, tlvsize, &offset, TLV_TYPE_STR_GPGID, destination_pgp_id); + + memcpy(&((unsigned char *)data)[offset],aes_key,16) ; + offset += 16 ; + + ok &= setRawUInt32(data, tlvsize, &offset, time_of_validity); + ok &= setRawUInt32(data, tlvsize, &offset, last_hit_time); + + if (offset != tlvsize) + { + ok = false; +#ifdef CHAT_DEBUG + std::cerr << "RsChatSerialiser::serialiseItem() Size Error! " << std::endl; +#endif + } + + return ok; +} bool RsChatStatusItem::serialise(void *data, uint32_t& pktsize) { uint32_t tlvsize = serial_size() ; @@ -1122,6 +1200,32 @@ RsPrivateChatMsgConfigItem::RsPrivateChatMsgConfigItem(void *data,uint32_t /*siz ok &= GetTlvWideString(data, rssize, &offset, TLV_TYPE_WSTR_MSG, message); ok &= getRawUInt32(data, rssize, &offset, &recvTime); +#ifdef CHAT_DEBUG + std::cerr << "Building new chat msg config item." << std::endl ; +#endif + if (offset != rssize) + std::cerr << "Size error while deserializing." << std::endl ; + if (!ok) + std::cerr << "Unknown error while deserializing." << std::endl ; +} +RsPrivateChatDistantInviteConfigItem::RsPrivateChatDistantInviteConfigItem(void *data,uint32_t /*size*/) + : RsChatItem(RS_PKT_SUBTYPE_DISTANT_INVITE_CONFIG) +{ + uint32_t offset = 8; // skip the header + uint32_t rssize = getRsItemSize(data); + bool ok = true ; + + /* get mandatory parts first */ + ok &= GetTlvString(data, rssize, &offset, TLV_TYPE_STR_KEY, hash); + ok &= GetTlvString(data, rssize, &offset, TLV_TYPE_STR_LINK, encrypted_radix64_string); + ok &= GetTlvString(data, rssize, &offset, TLV_TYPE_STR_GPGID, destination_pgp_id); + + memcpy(aes_key,&((unsigned char*)data)[offset],16) ; + offset += 16 ; + + ok &= getRawUInt32(data, rssize, &offset, &time_of_validity); + ok &= getRawUInt32(data, rssize, &offset, &last_hit_time); + #ifdef CHAT_DEBUG std::cerr << "Building new chat msg config item." << std::endl ; #endif @@ -1278,6 +1382,26 @@ void RsMsgTagType::clear() } +void RsPublicMsgInviteConfigItem::clear() +{ + hash.clear() ; + time_stamp = 0 ; +} +std::ostream& RsPublicMsgInviteConfigItem::print(std::ostream &out, uint16_t indent) +{ + printRsItemBase(out, "RsPublicMsgInviteConfigItem", indent); + uint16_t int_Indent = indent + 2; + + printIndent(out, int_Indent); + out << "hash : " << hash << std::endl; + + printIndent(out, int_Indent); + out << "timt : " << time_stamp << std::endl; + + printRsItemEnd(out, "RsPublicMsgInviteConfigItem", indent); + + return out; +} void RsMsgTags::clear() { msgId = 0; @@ -1476,7 +1600,15 @@ RsMsgItem *RsMsgSerialiser::deserialiseMsgItem(void *data, uint32_t *pktsize) return item; } +uint32_t RsMsgSerialiser::sizePublicMsgInviteConfigItem(RsPublicMsgInviteConfigItem* item) +{ + uint32_t s = 8; /* header */ + s += GetTlvStringSize(item->hash); + s += 4; /* time_stamp */ + + return s; +} uint32_t RsMsgSerialiser::sizeTagItem(RsMsgTagType* item) { @@ -1489,6 +1621,44 @@ uint32_t RsMsgSerialiser::sizeTagItem(RsMsgTagType* item) return s; } +bool RsMsgSerialiser::serialisePublicMsgInviteConfigItem(RsPublicMsgInviteConfigItem *item, void *data, uint32_t* pktsize) +{ + uint32_t tlvsize = sizePublicMsgInviteConfigItem(item); + uint32_t offset = 0; + + if (*pktsize < tlvsize) + return false; /* not enough space */ + + *pktsize = tlvsize; + + bool ok = true; + + ok &= setRsItemHeader(data, tlvsize, item->PacketId(), tlvsize); + +#ifdef RSSERIAL_DEBUG + std::cerr << "RsMsgSerialiser::serialiseMsgTagItem() Header: " << ok << std::endl; + std::cerr << "RsMsgSerialiser::serialiseMsgTagItem() Size: " << tlvsize << std::endl; +#endif + + /* skip the header */ + offset += 8; + + /* add mandatory parts first */ + + ok &= SetTlvString(data,tlvsize,&offset, TLV_TYPE_STR_HASH_SHA1, item->hash); + ok &= setRawUInt32(data,tlvsize,&offset, item->time_stamp); + + if (offset != tlvsize) + { + ok = false; +#ifdef RSSERIAL_DEBUG + std::cerr << "RsMsgSerialiser::serialiseMsgTagItem() Size Error! " << std::endl; +#endif + } + + return ok; +} + bool RsMsgSerialiser::serialiseTagItem(RsMsgTagType *item, void *data, uint32_t* pktsize) { @@ -1528,6 +1698,59 @@ bool RsMsgSerialiser::serialiseTagItem(RsMsgTagType *item, void *data, uint32_t* return ok; } +RsPublicMsgInviteConfigItem* RsMsgSerialiser::deserialisePublicMsgInviteConfigItem(void *data,uint32_t* pktsize) +{ + /* get the type and size */ + uint32_t rstype = getRsItemId(data); + uint32_t rssize = getRsItemSize(data); + + uint32_t offset = 0; + + if ((RS_PKT_VERSION_SERVICE != getRsItemVersion(rstype)) || + (RS_SERVICE_TYPE_MSG != getRsItemService(rstype)) || + (RS_PKT_SUBTYPE_MSG_INVITE != getRsItemSubType(rstype))) + { + return NULL; /* wrong type */ + } + + if (*pktsize < rssize) /* check size */ + return NULL; /* not enough data */ + + /* set the packet length */ + *pktsize = rssize; + + bool ok = true; + + /* ready to load */ + RsPublicMsgInviteConfigItem *item = new RsPublicMsgInviteConfigItem(); + item->clear(); + + /* skip the header */ + offset += 8; + + /* get mandatory parts first */ + ok &= GetTlvString(data,rssize,&offset,TLV_TYPE_STR_HASH_SHA1,item->hash); + + uint32_t ts ; + ok &= getRawUInt32(data, rssize, &offset, &ts) ; + item->time_stamp = ts ; + + if (offset != rssize) + { + /* error */ + delete item; + return NULL; + } + + if (!ok) + { + delete item; + return NULL; + } + + return item; +} + RsMsgTagType* RsMsgSerialiser::deserialiseTagItem(void *data,uint32_t* pktsize) { @@ -2006,7 +2229,7 @@ bool RsMsgSerialiser::serialise(RsItem *i, void *data, uint32_t *pktsize) RsMsgParentId* msp; RsMsgTagType *mtt; RsMsgTags *mts; - + RsPublicMsgInviteConfigItem *mtu; if (NULL != (mi = dynamic_cast(i))) { @@ -2028,6 +2251,10 @@ bool RsMsgSerialiser::serialise(RsItem *i, void *data, uint32_t *pktsize) { return serialiseMsgTagItem(mts, data, pktsize); } + else if (NULL != (mtu = dynamic_cast(i))) + { + return serialisePublicMsgInviteConfigItem(mtu, data, pktsize); + } return false; } @@ -2061,6 +2288,9 @@ RsItem* RsMsgSerialiser::deserialise(void *data, uint32_t *pktsize) case RS_PKT_SUBTYPE_MSG_TAG_TYPE: return deserialiseTagItem(data, pktsize); break; + case RS_PKT_SUBTYPE_MSG_INVITE: + return deserialisePublicMsgInviteConfigItem(data, pktsize); + break; case RS_PKT_SUBTYPE_MSG_TAGS: return deserialiseMsgTagItem(data, pktsize); break; diff --git a/libretroshare/src/serialiser/rsmsgitems.h b/libretroshare/src/serialiser/rsmsgitems.h index 3b9b06c75..3b2b75042 100644 --- a/libretroshare/src/serialiser/rsmsgitems.h +++ b/libretroshare/src/serialiser/rsmsgitems.h @@ -64,12 +64,14 @@ const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_INVITE = 0x0F ; const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_EVENT = 0x10 ; const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_LIST_deprecated2 = 0x11 ; // to be removed (deprecated since 02 Dec. 2012) const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_LIST = 0x12 ; +const uint8_t RS_PKT_SUBTYPE_DISTANT_INVITE_CONFIG = 0x13 ; // for defining tags themselves and msg tags const uint8_t RS_PKT_SUBTYPE_MSG_TAG_TYPE = 0x03; const uint8_t RS_PKT_SUBTYPE_MSG_TAGS = 0x04; const uint8_t RS_PKT_SUBTYPE_MSG_SRC_TAG = 0x05; const uint8_t RS_PKT_SUBTYPE_MSG_PARENT_TAG = 0x06; +const uint8_t RS_PKT_SUBTYPE_MSG_INVITE = 0x07; typedef uint64_t ChatLobbyId ; typedef uint64_t ChatLobbyMsgId ; @@ -314,6 +316,27 @@ class RsPrivateChatMsgConfigItem: public RsChatItem std::wstring message; uint32_t recvTime; }; +class RsPrivateChatDistantInviteConfigItem: public RsChatItem +{ + public: + RsPrivateChatDistantInviteConfigItem() :RsChatItem(RS_PKT_SUBTYPE_DISTANT_INVITE_CONFIG) {} + RsPrivateChatDistantInviteConfigItem(void *data,uint32_t size) ; // deserialization + + virtual ~RsPrivateChatDistantInviteConfigItem() {} + virtual void clear() {} + virtual std::ostream& print(std::ostream &out, uint16_t indent = 0); + + virtual bool serialise(void *data,uint32_t& size) ; // Isn't it better that items can serialize themselves ? + virtual uint32_t serial_size() ; // deserialise is handled using a constructor + + unsigned char aes_key[16] ; + std::string hash ; + std::string encrypted_radix64_string ; + std::string destination_pgp_id ; + uint32_t time_of_validity ; + uint32_t last_hit_time ; +}; + // This class contains activity info for the sending peer: active, idle, typing, etc. // @@ -384,6 +407,9 @@ const uint32_t RS_MSG_FLAGS_PARTIAL = 0x0400; const uint32_t RS_MSG_FLAGS_USER_REQUEST = 0x0800; const uint32_t RS_MSG_FLAGS_FRIEND_RECOMMENDATION = 0x1000; const uint32_t RS_MSG_FLAGS_SYSTEM = RS_MSG_FLAGS_USER_REQUEST | RS_MSG_FLAGS_FRIEND_RECOMMENDATION; +const uint32_t RS_MSG_FLAGS_RETURN_RECEPT = 0x2000; +const uint32_t RS_MSG_FLAGS_ENCRYPTED = 0x4000; +const uint32_t RS_MSG_FLAGS_DISTANT = 0x8000; class RsMsgItem: public RsItem { @@ -474,6 +500,24 @@ public: std::string srcId; }; +class RsPublicMsgInviteConfigItem : public RsItem +{ + +public: + RsPublicMsgInviteConfigItem() + : RsItem(RS_PKT_VERSION_SERVICE, RS_SERVICE_TYPE_MSG, + RS_PKT_SUBTYPE_MSG_INVITE) + { return;} + + std::ostream &print(std::ostream &out, uint16_t indent = 0); + + virtual ~RsPublicMsgInviteConfigItem() {} + virtual void clear(); + + std::string hash ; + time_t time_stamp ; +}; + class RsMsgParentId : public RsItem { @@ -498,45 +542,48 @@ public: class RsMsgSerialiser: public RsSerialType { public: - RsMsgSerialiser(bool bConfiguration = false) - :RsSerialType(RS_PKT_VERSION_SERVICE, RS_SERVICE_TYPE_MSG), m_bConfiguration (bConfiguration) - { return; } - - RsMsgSerialiser(uint16_t type) - :RsSerialType(RS_PKT_VERSION_SERVICE, type), m_bConfiguration (false) - { return; } - -virtual ~RsMsgSerialiser() { return; } - -virtual uint32_t size(RsItem *); -virtual bool serialise (RsItem *item, void *data, uint32_t *size); -virtual RsItem * deserialise(void *data, uint32_t *size); + RsMsgSerialiser(bool bConfiguration = false) + :RsSerialType(RS_PKT_VERSION_SERVICE, RS_SERVICE_TYPE_MSG), m_bConfiguration (bConfiguration) + { return; } + + RsMsgSerialiser(uint16_t type) + :RsSerialType(RS_PKT_VERSION_SERVICE, type), m_bConfiguration (false) + { return; } + + virtual ~RsMsgSerialiser() { return; } + + virtual uint32_t size(RsItem *); + virtual bool serialise (RsItem *item, void *data, uint32_t *size); + virtual RsItem * deserialise(void *data, uint32_t *size); private: -virtual uint32_t sizeMsgItem(RsMsgItem *); -virtual bool serialiseMsgItem (RsMsgItem *item, void *data, uint32_t *size); -virtual RsMsgItem *deserialiseMsgItem(void *data, uint32_t *size); + virtual uint32_t sizeMsgItem(RsMsgItem *); + virtual bool serialiseMsgItem (RsMsgItem *item, void *data, uint32_t *size); + virtual RsMsgItem *deserialiseMsgItem(void *data, uint32_t *size); -virtual uint32_t sizeTagItem(RsMsgTagType *); -virtual bool serialiseTagItem (RsMsgTagType *item, void *data, uint32_t *size); -virtual RsMsgTagType *deserialiseTagItem(void *data, uint32_t *size); + virtual uint32_t sizeTagItem(RsMsgTagType *); + virtual bool serialiseTagItem (RsMsgTagType *item, void *data, uint32_t *size); + virtual RsMsgTagType *deserialiseTagItem(void *data, uint32_t *size); -virtual uint32_t sizeMsgTagItem(RsMsgTags *); -virtual bool serialiseMsgTagItem (RsMsgTags *item, void *data, uint32_t *size); -virtual RsMsgTags *deserialiseMsgTagItem(void *data, uint32_t *size); + virtual uint32_t sizeMsgTagItem(RsMsgTags *); + virtual bool serialiseMsgTagItem (RsMsgTags *item, void *data, uint32_t *size); + virtual RsMsgTags *deserialiseMsgTagItem(void *data, uint32_t *size); -virtual uint32_t sizeMsgSrcIdItem(RsMsgSrcId *); -virtual bool serialiseMsgSrcIdItem (RsMsgSrcId *item, void *data, uint32_t *size); -virtual RsMsgSrcId *deserialiseMsgSrcIdItem(void *data, uint32_t *size); + virtual uint32_t sizeMsgSrcIdItem(RsMsgSrcId *); + virtual bool serialiseMsgSrcIdItem (RsMsgSrcId *item, void *data, uint32_t *size); + virtual RsMsgSrcId *deserialiseMsgSrcIdItem(void *data, uint32_t *size); -virtual uint32_t sizeMsgParentIdItem(RsMsgParentId *); -virtual bool serialiseMsgParentIdItem (RsMsgParentId *item, void *data, uint32_t *size); -virtual RsMsgParentId *deserialiseMsgParentIdItem(void *data, uint32_t *size); + virtual uint32_t sizeMsgParentIdItem(RsMsgParentId *); + virtual bool serialiseMsgParentIdItem (RsMsgParentId *item, void *data, uint32_t *size); + virtual RsMsgParentId *deserialiseMsgParentIdItem(void *data, uint32_t *size); + virtual uint32_t sizePublicMsgInviteConfigItem(RsPublicMsgInviteConfigItem *) ; + virtual bool serialisePublicMsgInviteConfigItem(RsPublicMsgInviteConfigItem *item, void *data, uint32_t *size); + virtual RsPublicMsgInviteConfigItem *deserialisePublicMsgInviteConfigItem(void *data, uint32_t *size); - bool m_bConfiguration; // is set to true for saving configuration (enables serialising msgId) + bool m_bConfiguration; // is set to true for saving configuration (enables serialising msgId) }; /**************************************************************************/ diff --git a/libretroshare/src/services/p3chatservice.cc b/libretroshare/src/services/p3chatservice.cc index 59430723b..cc33e3452 100644 --- a/libretroshare/src/services/p3chatservice.cc +++ b/libretroshare/src/services/p3chatservice.cc @@ -24,11 +24,18 @@ */ #include +#include "openssl/rand.h" +#include "pgp/rscertificate.h" +#include "pqi/authgpg.h" #include "util/rsdir.h" +#include "util/radix64.h" +#include "util/rsaes.h" #include "util/rsrandom.h" #include "util/rsstring.h" +#include "turtle/p3turtle.h" #include "retroshare/rsiface.h" #include "retroshare/rspeers.h" +#include "retroshare/rsstatus.h" #include "pqi/pqibin.h" #include "pqi/pqinotify.h" #include "pqi/pqistore.h" @@ -40,6 +47,7 @@ /**** * #define CHAT_DEBUG 1 + * #define DEBUG_DISTANT_CHAT 1 ****/ static const int CONNECTION_CHALLENGE_MAX_COUNT = 20 ; // sends a connexion challenge every 20 messages @@ -52,18 +60,30 @@ static const time_t MAX_DELAY_BETWEEN_LOBBY_KEEP_ALIVE = 120 ; // send keep al static const time_t MAX_KEEP_PUBLIC_LOBBY_RECORD = 60 ; // keep inactive lobbies records for 60 secs max. static const time_t MIN_DELAY_BETWEEN_PUBLIC_LOBBY_REQ = 20 ; // don't ask for lobby list more than once every 30 secs. +static const time_t DISTANT_CHAT_CLEANING_PERIOD = 60 ; // don't ask for lobby list more than once every 30 secs. +static const uint32_t DISTANT_CHAT_AES_KEY_SIZE = 16 ; // size of AES encryption key for distant chat. +static const uint32_t DISTANT_CHAT_HASH_SIZE = 20 ; // This is sha1 size in bytes. + p3ChatService::p3ChatService(p3LinkMgr *lm, p3HistoryMgr *historyMgr) :p3Service(RS_SERVICE_TYPE_CHAT), p3Config(CONFIG_TYPE_CHAT), mChatMtx("p3ChatService"), mLinkMgr(lm) , mHistoryMgr(historyMgr) { - addSerialType(new RsChatSerialiser()); - + _serializer = new RsChatSerialiser() ; _own_avatar = NULL ; _custom_status_string = "" ; _time_shift_average = 0.0f ; _default_nick_name = rsPeers->getPeerName(rsPeers->getOwnId()); _should_reset_lobby_counts = false ; + mTurtle = NULL ; last_visible_lobby_info_request_time = 0 ; + + addSerialType(_serializer) ; +} + +void p3ChatService::connectToTurtleRouter(p3turtle *tr) +{ + mTurtle = tr ; + tr->registerTunnelService(this) ; } int p3ChatService::tick() @@ -71,15 +91,21 @@ int p3ChatService::tick() if(receivedItems()) receiveChatQueue(); - static time_t last_clean_time = 0 ; + static time_t last_clean_time_lobby = 0 ; + static time_t last_clean_time_dchat = 0 ; + time_t now = time(NULL) ; - if(last_clean_time + LOBBY_CACHE_CLEANING_PERIOD < now) + if(last_clean_time_lobby + LOBBY_CACHE_CLEANING_PERIOD < now) { cleanLobbyCaches() ; - last_clean_time = now ; + last_clean_time_lobby = now ; + } + if(last_clean_time_dchat + DISTANT_CHAT_CLEANING_PERIOD < now) + { + cleanDistantChatInvites() ; + last_clean_time_dchat = now ; } - return 0; } @@ -221,10 +247,27 @@ void p3ChatService::sendStatusString( const std::string& id , const std::string& std::cerr << "sending chat status packet:" << std::endl ; cs->print(std::cerr) ; #endif - sendItem(cs); + sendPrivateChatItem(cs); } } +void p3ChatService::sendPrivateChatItem(RsChatItem *item) +{ + bool found = false ; + + { + RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + + if(_distant_chat_peers.find(item->PeerId()) != _distant_chat_peers.end()) + found = true ; + } + + if(found) + sendTurtleData(item) ; + else + sendItem(item) ; +} + void p3ChatService::checkSizeAndSendMessage_deprecated(RsChatMsgItem *msg) { // We check the message item, and possibly split it into multiple messages, if the message is too big. @@ -248,9 +291,9 @@ void p3ChatService::checkSizeAndSendMessage_deprecated(RsChatMsgItem *msg) // Indicate that the message is to be continued. // item->chatFlags |= RS_CHAT_FLAG_PARTIAL_MESSAGE ; - sendItem(item) ; + sendPrivateChatItem(item) ; } - sendItem(msg) ; + sendPrivateChatItem(msg) ; } // This function should be used for all types of chat messages. But this requires a non backward compatible change in // chat protocol. To be done for version 0.6 @@ -374,6 +417,18 @@ bool p3ChatService::isLobbyId(const std::string& id,ChatLobbyId& lobby_id) return false ; } +bool p3ChatService::isOnline(const std::string& id) +{ + // check if the id is a tunnel id or a peer id. + + uint32_t status ; + std::string pgp_id ; + + if(!getDistantChatStatus(id,status,pgp_id)) + return mLinkMgr->isOnline(id) ; + + return true ; +} bool p3ChatService::sendPrivateChat(const std::string &id, const std::wstring &msg) { @@ -398,7 +453,8 @@ bool p3ChatService::sendPrivateChat(const std::string &id, const std::wstrin ci->recvTime = ci->sendTime; ci->message = msg; - if (!mLinkMgr->isOnline(id)) { + if(!isOnline(id)) + { /* peer is offline, add to outgoing list */ { RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ @@ -471,7 +527,7 @@ bool p3ChatService::sendPrivateChat(const std::string &id, const std::wstrin #endif RsChatStatusItem *cs = makeOwnCustomStateStringItem() ; cs->PeerId(id) ; - sendItem(cs) ; + sendPrivateChatItem(cs) ; } return true; @@ -608,20 +664,24 @@ void p3ChatService::receiveChatQueue() RsItem *item ; while(NULL != (item=recvItem())) - { -#ifdef CHAT_DEBUG - std::cerr << "p3ChatService::receiveChatQueue() Item:" << (void*)item << std::endl ; -#endif - // RsChatMsgItems needs dynamic_cast, since they have derived siblings. - // - RsChatMsgItem *ci = dynamic_cast(item) ; - if(ci != NULL) - { - if(! handleRecvChatMsgItem(ci)) - delete ci ; + handleIncomingItem(item) ; +} - continue ; // don't delete! It's handled by handleRecvChatMsgItem in some specific cases only. - } +void p3ChatService::handleIncomingItem(RsItem *item) +{ +#ifdef CHAT_DEBUG + std::cerr << "p3ChatService::receiveChatQueue() Item:" << (void*)item << std::endl ; +#endif + // RsChatMsgItems needs dynamic_cast, since they have derived siblings. + // + RsChatMsgItem *ci = dynamic_cast(item) ; + if(ci != NULL) + { + if(! handleRecvChatMsgItem(ci)) + delete ci ; + + return ; // don't delete! It's handled by handleRecvChatMsgItem in some specific cases only. + } switch(item->PacketSubType()) { @@ -647,7 +707,6 @@ void p3ChatService::receiveChatQueue() } } delete item ; - } } void p3ChatService::handleRecvChatLobbyListRequest(RsChatLobbyListRequestItem *clr) @@ -1479,17 +1538,19 @@ void p3ChatService::getOwnAvatarJpegData(unsigned char *& data,int& size) std::string p3ChatService::getCustomStateString(const std::string& peer_id) { - // should be a Mutex here. - RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ - - std::map::iterator it = _state_strings.find(peer_id) ; - - // has it. Return it strait away. - // - if(it!=_state_strings.end()) { - it->second._peer_is_new = false ; - return it->second._custom_status_string ; + // should be a Mutex here. + RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + + std::map::iterator it = _state_strings.find(peer_id) ; + + // has it. Return it strait away. + // + if(it!=_state_strings.end()) + { + it->second._peer_is_new = false ; + return it->second._custom_status_string ; + } } sendCustomStateRequest(peer_id); @@ -1498,33 +1559,35 @@ std::string p3ChatService::getCustomStateString(const std::string& peer_id) void p3ChatService::getAvatarJpegData(const std::string& peer_id,unsigned char *& data,int& size) { - // should be a Mutex here. - RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ - - std::map::const_iterator it = _avatars.find(peer_id) ; - -#ifdef CHAT_DEBUG - std::cerr << "p3chatservice:: avatar for peer " << peer_id << " requested from above. " << std::endl ; -#endif - // has avatar. Return it straight away. - // - if(it!=_avatars.end()) { - uint32_t s=0 ; - it->second->toUnsignedChar(data,s) ; - size = s ; - it->second->_peer_is_new = false ; -#ifdef CHAT_DEBUG - std::cerr << "Already has avatar. Returning it" << std::endl ; -#endif - return ; - } else { -#ifdef CHAT_DEBUG - std::cerr << "No avatar for this peer. Requesting it by sending request packet." << std::endl ; -#endif - } + // should be a Mutex here. + RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ - sendAvatarRequest(peer_id); + std::map::const_iterator it = _avatars.find(peer_id) ; + +#ifdef CHAT_DEBUG + std::cerr << "p3chatservice:: avatar for peer " << peer_id << " requested from above. " << std::endl ; +#endif + // has avatar. Return it straight away. + // + if(it!=_avatars.end()) + { + uint32_t s=0 ; + it->second->toUnsignedChar(data,s) ; + size = s ; + it->second->_peer_is_new = false ; +#ifdef CHAT_DEBUG + std::cerr << "Already has avatar. Returning it" << std::endl ; +#endif + return ; + } else { +#ifdef CHAT_DEBUG + std::cerr << "No avatar for this peer. Requesting it by sending request packet." << std::endl ; +#endif + } + } + + sendAvatarRequest(peer_id); } void p3ChatService::sendAvatarRequest(const std::string& peer_id) @@ -1543,7 +1606,7 @@ void p3ChatService::sendAvatarRequest(const std::string& peer_id) std::cerr << std::endl; #endif - sendItem(ci); + sendPrivateChatItem(ci); } void p3ChatService::sendCustomStateRequest(const std::string& peer_id){ @@ -1559,7 +1622,7 @@ void p3ChatService::sendCustomStateRequest(const std::string& peer_id){ std::cerr << std::endl; #endif - sendItem(cs); + sendPrivateChatItem(cs); } RsChatStatusItem *p3ChatService::makeOwnCustomStateStringItem() @@ -1601,7 +1664,7 @@ void p3ChatService::sendAvatarJpegData(const std::string& peer_id) std::cerr << std::endl; #endif - sendItem(ci) ; + sendPrivateChatItem(ci) ; } else { #ifdef CHAT_DEBUG @@ -1619,7 +1682,7 @@ std::cerr << "p3chatservice: sending requested status string for peer " << peer_ RsChatStatusItem *cs = makeOwnCustomStateStringItem(); cs->PeerId(peer_id); - sendItem(cs); + sendPrivateChatItem(cs); } bool p3ChatService::loadList(std::list& load) @@ -1683,6 +1746,24 @@ bool p3ChatService::loadList(std::list& load) continue; } + RsPrivateChatDistantInviteConfigItem *ditem = NULL ; + + if(NULL != (ditem = dynamic_cast(*it))) + { + DistantChatInvite invite ; + + memcpy(invite.aes_key,ditem->aes_key,DISTANT_CHAT_AES_KEY_SIZE) ; + invite.encrypted_radix64_string = ditem->encrypted_radix64_string ; + invite.destination_pgp_id = ditem->destination_pgp_id ; + invite.time_of_validity = ditem->time_of_validity ; + invite.last_hit_time = ditem->last_hit_time ; + + _distant_chat_invites[ditem->hash] = invite ; + + delete *it ; + continue ; + } + RsConfigKeyValueSet *vitem = NULL ; if(NULL != (vitem = dynamic_cast(*it))) @@ -1746,6 +1827,21 @@ bool p3ChatService::saveList(bool& cleanup, std::list& list) list.push_back(ci); } + /* save ongoing distant chat invites */ + + for(std::map::const_iterator it(_distant_chat_invites.begin());it!=_distant_chat_invites.end();++it) + { + RsPrivateChatDistantInviteConfigItem *ei = new RsPrivateChatDistantInviteConfigItem ; + ei->hash = it->first ; + memcpy(ei->aes_key,it->second.aes_key,DISTANT_CHAT_AES_KEY_SIZE) ; + ei->encrypted_radix64_string = it->second.encrypted_radix64_string ; + ei->destination_pgp_id = it->second.destination_pgp_id ; + ei->time_of_validity = it->second.time_of_validity ; + ei->last_hit_time = it->second.last_hit_time ; + + list.push_back(ei) ; + } + RsConfigKeyValueSet *vitem = new RsConfigKeyValueSet ; RsTlvKeyValue kv; kv.key = "DEFAULT_NICK_NAME" ; @@ -1780,10 +1876,14 @@ void p3ChatService::statusChange(const std::list &plist) for (it = plist.begin(); it != plist.end(); it++) { if (it->state & RS_PEER_S_FRIEND) { if (it->actions & RS_PEER_CONNECTED) { + /* send the saved outgoing messages */ bool changed = false; - if (privateOutgoingList.size()) { + std::vector to_send ; + + if (privateOutgoingList.size()) + { RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ std::string ownId = mLinkMgr->getOwnId(); @@ -1795,7 +1895,7 @@ void p3ChatService::statusChange(const std::list &plist) if (c->PeerId() == it->id) { mHistoryMgr->addMessage(false, c->PeerId(), ownId, c); - checkSizeAndSendMessage_deprecated(c); // delete item + to_send.push_back(c) ; changed = true; @@ -1808,6 +1908,9 @@ void p3ChatService::statusChange(const std::list &plist) } } /* UNLOCKED */ + for(uint32_t i=0;igetNotify().notifyListChange(NOTIFY_LIST_PRIVATE_OUTGOING_CHAT, NOTIFY_TYPE_DEL); @@ -2745,4 +2848,534 @@ void p3ChatService::cleanLobbyCaches() sendConnectionChallenge(*it) ; } +bool p3ChatService::handleTunnelRequest(const std::string& hash,const std::string& peer_id) +{ + RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + + std::map::iterator it = _distant_chat_invites.find(hash) ; + +#ifdef DEBUG_DISTANT_CHAT + std::cerr << "p3ChatService::handleTunnelRequest: received tunnel request for hash " << hash << std::endl; +#endif + + if(it == _distant_chat_invites.end()) + return false ; + + it->second.last_hit_time = time(NULL) ; + return true ; +} + +void p3ChatService::addVirtualPeer(const TurtleFileHash& hash,const TurtleVirtualPeerId& virtual_peer_id,RsTurtleGenericTunnelItem::Direction dir) +{ +#ifdef DEBUG_DISTANT_CHAT + std::cerr << "p3ChatService:: adding new virtual peer " << virtual_peer_id << " for hash " << hash << std::endl; +#endif + time_t now = time(NULL) ; + + if(dir == RsTurtleGenericTunnelItem::DIRECTION_SERVER) + { + RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + +#ifdef DEBUG_DISTANT_CHAT + std::cerr << " Side is in direction to server." << std::endl; +#endif + + std::map::iterator it = _distant_chat_peers.find(hash) ; + + if(it == _distant_chat_peers.end()) + { + std::cerr << "(EE) Cannot add virtual peer for hash " << hash << ": no chat invite found for that hash." << std::endl; + return ; + } + + it->second.last_contact = now ; + it->second.status = RS_DISTANT_CHAT_STATUS_TUNNEL_OK ; + it->second.virtual_peer_id = virtual_peer_id ; + +#ifdef DEBUG_DISTANT_CHAT + std::cerr << "(II) Adding virtual peer " << virtual_peer_id << " for chat hash " << hash << std::endl; +#endif + } + + if(dir == RsTurtleGenericTunnelItem::DIRECTION_CLIENT) + { + RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + +#ifdef DEBUG_DISTANT_CHAT + std::cerr << " Side is in direction to client." << std::endl; + std::cerr << " Initing encryption parameters from existing distant chat invites." << std::endl; +#endif + + std::map::iterator it = _distant_chat_invites.find(hash) ; + + if(it == _distant_chat_invites.end()) + { + std::cerr << "(EE) Cannot find distant chat invite for hash " << hash << ": no chat invite found for that hash." << std::endl; + return ; + } + DistantChatPeerInfo info ; + info.last_contact = now ; + info.status = RS_DISTANT_CHAT_STATUS_TUNNEL_OK ; + info.virtual_peer_id = virtual_peer_id ; + info.pgp_id = it->second.destination_pgp_id ; + memcpy(info.aes_key,it->second.aes_key,DISTANT_CHAT_AES_KEY_SIZE) ; + + _distant_chat_peers[hash] = info ; + it->second.last_hit_time = now ; + } + + rsicontrol->getNotify().notifyChatStatus(hash,"tunnel is up again!",true) ; + rsicontrol->getNotify().notifyPeerStatusChanged(hash,RS_STATUS_ONLINE) ; + + getPqiNotify()->AddPopupMessage(RS_POPUP_CHAT, hash, "Distant peer", "Conversation starts..."); +} + +void p3ChatService::removeVirtualPeer(const TurtleFileHash& hash,const TurtleVirtualPeerId& virtual_peer_id) +{ + { + RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + + std::map::iterator it = _distant_chat_peers.find(hash) ; + + if(it == _distant_chat_peers.end()) + { + std::cerr << "(EE) Cannot remove virtual peer " << virtual_peer_id << ": not found in chat list!!" << std::endl; + return ; + } + + it->second.status = RS_DISTANT_CHAT_STATUS_TUNNEL_DN ; + } + rsicontrol->getNotify().notifyChatStatus(hash,"tunnel is down...",true) ; + rsicontrol->getNotify().notifyPeerStatusChanged(hash,RS_STATUS_OFFLINE) ; +} + +#ifdef DEBUG_DISTANT_CHAT +static void printBinaryData(void *data,uint32_t size) +{ + static const char outl[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' } ; + + for(uint32_t j = 0; j < size; j++) + { + std::cerr << outl[ ( ((uint8_t*)data)[j]>>4) ] ; + std::cerr << outl[ ((uint8_t*)data)[j] & 0xf ] ; + } +} +#endif + +void p3ChatService::receiveTurtleData( RsTurtleGenericTunnelItem *gitem,const std::string& hash, + const std::string& virtual_peer_id,RsTurtleGenericTunnelItem::Direction direction) +{ +#ifdef DEBUG_DISTANT_CHAT + std::cerr << "p3ChatService::receiveTurtleData(): Received turtle data. " << std::endl; + std::cerr << " hash = " << hash << std::endl; + std::cerr << " vpid = " << virtual_peer_id << std::endl; + std::cerr << " dir = " << virtual_peer_id << std::endl; +#endif + + RsTurtleGenericDataItem *item = dynamic_cast(gitem) ; + + if(item == NULL) + { + std::cerr << "(EE) item is not a data item. That is an error." << std::endl; + return ; + } +#ifdef DEBUG_DISTANT_CHAT + std::cerr << " size = " << item->data_size << std::endl; + std::cerr << " data = " << (void*)item->data_bytes << std::endl; + std::cerr << " IV = " << std::hex << *(uint64_t*)item->data_bytes << std::dec << std::endl; + std::cerr << " data = " ; + + printBinaryData(item->data_bytes,item->data_size) ; + std::cerr << std::endl; +#endif + + uint8_t aes_key[DISTANT_CHAT_AES_KEY_SIZE] ; + + { + RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + std::map::iterator it = _distant_chat_peers.find(hash) ; + + if(it == _distant_chat_peers.end()) + { + std::cerr << "(EE) item is not coming out of a registered tunnel. Weird. hash=" << hash << ", peer id = " << virtual_peer_id << std::endl; + return ; + } + it->second.last_contact = time(NULL) ; + memcpy(aes_key,it->second.aes_key,DISTANT_CHAT_AES_KEY_SIZE) ; + it->second.status = RS_DISTANT_CHAT_STATUS_CAN_TALK ; + } + + // Call the AES crypto module + // - the IV is the first 8 bytes of item->data_bytes + + if(item->data_size < 8) + { + std::cerr << "(EE) item encrypted data stream is too small: size = " << item->data_size << std::endl; + return ; + } + uint32_t decrypted_size = RsAES::get_buffer_size(item->data_size-8); + uint8_t *decrypted_data = new uint8_t[decrypted_size]; + +#ifdef DEBUG_DISTANT_CHAT + std::cerr << " Using IV: " << std::hex << *(uint64_t*)item->data_bytes << std::dec << std::endl; + std::cerr << " Decrypted buffer size: " << decrypted_size << std::endl; + std::cerr << " key : " ; printBinaryData(aes_key,16) ; std::cerr << std::endl; + std::cerr << " data : " ; printBinaryData(item->data_bytes,item->data_size) ; std::cerr << std::endl; +#endif + + if(!RsAES::aes_decrypt_8_16((uint8_t*)item->data_bytes+8,item->data_size-8,aes_key,(uint8_t*)item->data_bytes,decrypted_data,decrypted_size)) + { + std::cerr << "(EE) packet decryption failed." << std::endl; + delete[] decrypted_data ; + return ; + } + +#ifdef DEBUG_DISTANT_CHAT + std::cerr << "(II) Decrypted data: size=" << decrypted_size << std::endl; +#endif + + // Now try deserialise the decrypted data to make an RsItem out of it. + // + RsItem *citem = _serializer->deserialise(decrypted_data,&decrypted_size) ; + delete[] decrypted_data ; + + if(citem == NULL) + { + std::cerr << "(EE) item could not be de-serialized. That is an error." << std::endl; + return ; + } + + // Setup the virtual peer to be the origin, and pass it on. + // + citem->PeerId(hash) ; + handleIncomingItem(citem) ; // Treats the item, and deletes it +} + +void p3ChatService::sendTurtleData(RsChatItem *item) +{ +#ifdef DEBUG_DISTANT_CHAT + std::cerr << "p3ChatService::sendTurtleData(): try sending item " << (void*)item << " to tunnel " << item->PeerId() << std::endl; +#endif + + uint32_t rssize = item->serial_size(); + uint8_t *buff = new uint8_t[rssize] ; + + if(!item->serialise(buff,rssize)) + { + std::cerr << "(EE) p3ChatService::sendTurtleData(): Could not serialise item!" << std::endl; + delete[] buff ; + return ; + } +#ifdef DEBUG_DISTANT_CHAT + std::cerr << " Serialized item has size " << rssize << std::endl; +#endif + + uint8_t aes_key[DISTANT_CHAT_AES_KEY_SIZE] ; + std::string virtual_peer_id ; + + { + RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + std::map::iterator it = _distant_chat_peers.find(item->PeerId()) ; + + if(it == _distant_chat_peers.end()) + { + std::cerr << "(EE) item is not coming out of a registered tunnel. Weird. peer id = " << virtual_peer_id << std::endl; + delete[] buff ; + return ; + } + it->second.last_contact = time(NULL) ; + virtual_peer_id = it->second.virtual_peer_id ; + memcpy(aes_key,it->second.aes_key,DISTANT_CHAT_AES_KEY_SIZE) ; + } +#ifdef DEBUG_DISTANT_CHAT + std::cerr << "p3ChatService::sendTurtleData(): tunnel found. Encrypting data." << std::endl; +#endif + + // Now encrypt this data using AES. + // + uint8_t *encrypted_data = new uint8_t[RsAES::get_buffer_size(rssize)]; + uint32_t encrypted_size = RsAES::get_buffer_size(rssize); + + uint64_t IV = RSRandom::random_u64() ; // make a random 8 bytes IV + +#ifdef DEBUG_DISTANT_CHAT + std::cerr << " Using IV: " << std::hex << IV << std::dec << std::endl; + std::cerr << " Using Key: " ; printBinaryData(aes_key,16) ; std::cerr << std::endl; +#endif + + if(!RsAES::aes_crypt_8_16(buff,rssize,aes_key,(uint8_t*)&IV,encrypted_data,encrypted_size)) + { + std::cerr << "(EE) packet encryption failed." << std::endl; + delete[] encrypted_data ; + delete[] buff ; + return ; + } + delete[] buff ; + + // make a TurtleGenericData item out of it: + // + RsTurtleGenericDataItem *gitem = new RsTurtleGenericDataItem ; + + gitem->data_size = encrypted_size + 8 ; + gitem->data_bytes = malloc(gitem->data_size) ; + + memcpy(gitem->data_bytes ,&IV,8) ; + memcpy(gitem->data_bytes+8,encrypted_data,encrypted_size) ; + + delete[] encrypted_data ; + delete item ; + +#ifdef DEBUG_DISTANT_CHAT + std::cerr << "p3ChatService::sendTurtleData(): Sending through virtual peer: " << virtual_peer_id << std::endl; + std::cerr << " gitem->data_size = " << gitem->data_size << std::endl; + std::cerr << " data = " ; + + printBinaryData(gitem->data_bytes,gitem->data_size) ; + std::cerr << std::endl; +#endif + + mTurtle->sendTurtleData(virtual_peer_id,gitem) ; +} + +bool p3ChatService::createDistantChatInvite(const std::string& pgp_id,time_t time_of_validity,std::string& encrypted_radix64_string) +{ + // create the invite + + time_t now = time(NULL) ; + + DistantChatInvite invite ; + invite.time_of_validity = now + time_of_validity ; + invite.last_hit_time = now ; + + RAND_bytes( (unsigned char *)&invite.aes_key[0],DISTANT_CHAT_AES_KEY_SIZE ) ; // generate a random AES encryption key + + // Create a random hash for that invite. + // + unsigned char hash_bytes[DISTANT_CHAT_HASH_SIZE] ; + RAND_bytes( hash_bytes, DISTANT_CHAT_HASH_SIZE) ; + + std::string hash = t_RsGenericIdType(hash_bytes).toStdString(false) ; + +#ifdef DEBUG_DISTANT_CHAT + std::cerr << "Created new distant chat invite: " << std::endl; + std::cerr << " validity time stamp = " << invite.time_of_validity << std::endl; + std::cerr << " hash = " << hash << std::endl; + std::cerr << " encryption key = " ; + static const char outl[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' } ; + for(uint32_t j = 0; j < 16; j++) { std::cerr << outl[ (invite.aes_key[j]>>4) ] ; std::cerr << outl[ invite.aes_key[j] & 0xf ] ; } + std::cerr << std::endl; +#endif + + // Now encrypt the data to create the link info. We need + // + // [E] - the hash + // [E] - the aes key + // [E] - the signature + // - pgp id + // - timestamp + // + // The link will be + // + // retroshare://chat?time_stamp=3243242&private_data=[radix64 string] + + uint32_t header_size = DISTANT_CHAT_AES_KEY_SIZE + DISTANT_CHAT_HASH_SIZE + KEY_ID_SIZE; + unsigned char *data = new unsigned char[header_size+400] ; + + PGPIdType OwnId(AuthGPG::getAuthGPG()->getGPGOwnId()); + + memcpy(data ,hash_bytes ,DISTANT_CHAT_HASH_SIZE) ; + memcpy(data+DISTANT_CHAT_HASH_SIZE ,invite.aes_key ,DISTANT_CHAT_AES_KEY_SIZE) ; + memcpy(data+DISTANT_CHAT_HASH_SIZE+DISTANT_CHAT_AES_KEY_SIZE,OwnId.toByteArray(),KEY_ID_SIZE) ; + +#ifdef DEBUG_DISTANT_CHAT + std::cerr << "Performing signature " << std::endl; +#endif + uint32_t signlen = 400; + + if(!AuthGPG::getAuthGPG()->SignDataBin(data,header_size,data+header_size,&signlen)) + return false ; + +#ifdef DEBUG_DISTANT_CHAT + std::cerr << "Signature length = " << signlen << std::endl; +#endif + + // Then encrypt the whole data into a single string. + + unsigned char *encrypted_data = new unsigned char[2000] ; + uint32_t encrypted_size = 2000 ; + + if(!AuthGPG::getAuthGPG()->encryptDataBin(pgp_id,(unsigned char *)data,signlen+header_size,encrypted_data,&encrypted_size)) + return false ; + +#ifdef DEBUG_DISTANT_CHAT + std::cerr << "Encrypted data size: " << encrypted_size << std::endl; +#endif + + Radix64::encode((const char *)encrypted_data,encrypted_size,invite.encrypted_radix64_string) ; + invite.destination_pgp_id = pgp_id ; + + { + RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + _distant_chat_invites[hash] = invite ; + } + + encrypted_radix64_string = invite.encrypted_radix64_string ; +#ifdef DEBUG_DISTANT_CHAT + std::cerr << "Encrypted radix64 string: " << invite.encrypted_radix64_string << std::endl; +#endif + + IndicateConfigChanged(); + return true ; +} + +bool p3ChatService::initiateDistantChatConnexion(const std::string& encrypted_str,std::string& hash,uint32_t& error_code) +{ + RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + + // Un-radix the string. + // + char *encrypted_data_bin = NULL ; + size_t encrypted_data_len ; + + Radix64::decode(encrypted_str,encrypted_data_bin,encrypted_data_len) ; + + // Decrypt it. + // + uint32_t data_size = encrypted_data_len+1000; + unsigned char *data = new unsigned char[data_size] ; + + if(!AuthGPG::getAuthGPG()->decryptDataBin((unsigned char *)encrypted_data_bin,encrypted_data_len,data,&data_size)) + { + error_code = RS_DISTANT_CHAT_ERROR_DECRYPTION_FAILED ; + return false ; + } + delete[] encrypted_data_bin ; + +#ifdef DEBUG_DISTANT_CHAT + std::cerr << "Chat invite was successfuly decrypted!" << std::endl; +#endif + + uint32_t header_size = DISTANT_CHAT_HASH_SIZE + DISTANT_CHAT_AES_KEY_SIZE + KEY_ID_SIZE ; + + PGPIdType pgp_id( data + DISTANT_CHAT_HASH_SIZE + DISTANT_CHAT_AES_KEY_SIZE ) ; + +#ifdef DEBUG_DISTANT_CHAT + std::cerr << "Got this PGP id: " << pgp_id.toStdString() << std::endl; +#endif + + PGPFingerprintType fingerprint ; + if(!AuthGPG::getAuthGPG()->getKeyFingerprint(pgp_id,fingerprint)) + { + error_code = RS_DISTANT_CHAT_ERROR_UNKNOWN_KEY ; + return false ; + } + + if(!AuthGPG::getAuthGPG()->VerifySignBin(data,header_size,data+header_size,data_size-header_size,fingerprint.toStdString())) + { + error_code = RS_DISTANT_CHAT_ERROR_SIGNATURE_MISMATCH ; + return false ; + } +#ifdef DEBUG_DISTANT_CHAT + std::cerr << "Signature successfuly verified!" << std::endl; +#endif + + hash = t_RsGenericIdType(data).toStdString(false) ; + DistantChatPeerInfo info ; + + info.last_contact = time(NULL) ; + info.status = RS_DISTANT_CHAT_STATUS_TUNNEL_DN ; + info.pgp_id = pgp_id.toStdString() ; + memcpy(info.aes_key,data+DISTANT_CHAT_HASH_SIZE,DISTANT_CHAT_AES_KEY_SIZE) ; + + _distant_chat_peers[hash] = info ; + + delete[] data ; + + // Now ask the turtle router to manage a tunnel for that hash. + +#ifdef DEBUG_DISTANT_CHAT + std::cerr << "Asking turtle router to monitor tunnels for hash " << hash << std::endl; +#endif + + mTurtle->monitorTunnels(hash,this) ; + + // And notify about chatting. + + error_code = RS_DISTANT_CHAT_ERROR_NO_ERROR ; + return true ; +} + +void p3ChatService::cleanDistantChatInvites() +{ + RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + + time_t now = time(NULL) ; + +#ifdef DEBUG_DISTANT_CHAT + std::cerr << "p3ChatService::cleanDistantChatInvites: " << std::endl; +#endif + + for(std::map::iterator it(_distant_chat_invites.begin());it!=_distant_chat_invites.end(); ) + if(it->second.time_of_validity < now) + { +#ifdef DEBUG_DISTANT_CHAT + std::cerr << " Removing hash " << it->first << std::endl; +#endif + std::map::iterator tmp(it) ; + ++it ; + _distant_chat_invites.erase(tmp) ; + } + else + { +#ifdef DEBUG_DISTANT_CHAT + std::cerr << " Keeping hash " << it->first << std::endl; +#endif + ++it ; + } +} + +bool p3ChatService::getDistantChatInviteList(std::vector& invites) +{ + invites.clear() ; + + RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + for(std::map::const_iterator it(_distant_chat_invites.begin());it!=_distant_chat_invites.end();++it) + { + DistantChatInviteInfo info ; + info.hash = it->first ; + info.encrypted_radix64_string = it->second.encrypted_radix64_string ; + info.time_of_validity = it->second.time_of_validity ; + info.destination_pgp_id = it->second.destination_pgp_id ; + + invites.push_back(info); + } + return true ; +} + +bool p3ChatService::getDistantChatStatus(const std::string& hash,uint32_t& status,std::string& pgp_id) +{ + RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + + std::map::const_iterator it = _distant_chat_peers.find(hash) ; + + if(it == _distant_chat_peers.end()) + return false ; + + status = it->second.status ; + pgp_id = it->second.pgp_id ; + + return true ; +} + + + + + + + + + + + + diff --git a/libretroshare/src/services/p3chatservice.h b/libretroshare/src/services/p3chatservice.h index 9337f97dc..ed4481828 100644 --- a/libretroshare/src/services/p3chatservice.h +++ b/libretroshare/src/services/p3chatservice.h @@ -33,10 +33,13 @@ #include "serialiser/rsmsgitems.h" #include "services/p3service.h" +#include "pgp/pgphandler.h" +#include "turtle/turtleclientservice.h" #include "retroshare/rsmsgs.h" class p3LinkMgr; class p3HistoryMgr; +class p3turtle ; //!The basic Chat service. /** @@ -45,7 +48,7 @@ class p3HistoryMgr; * This service uses rsnotify (callbacks librs clients (e.g. rs-gui)) * @see NotifyBase */ -class p3ChatService: public p3Service, public p3Config, public pqiMonitor +class p3ChatService: public p3Service, public p3Config, public pqiMonitor, public RsTurtleClientService { public: p3ChatService(p3LinkMgr *cm, p3HistoryMgr *historyMgr); @@ -183,6 +186,7 @@ class p3ChatService: public p3Service, public p3Config, public pqiMonitor virtual void saveDone(); virtual bool loadList(std::list& load) ; + bool isOnline(const std::string& id) ; private: RsMutex mChatMtx; @@ -191,6 +195,7 @@ class p3ChatService: public p3Service, public p3Config, public pqiMonitor // Receive chat queue void receiveChatQueue(); + void handleIncomingItem(RsItem *); // called by the former, and turtle handler for incoming encrypted items void initRsChatInfo(RsChatMsgItem *c, ChatInfo &i); @@ -289,9 +294,69 @@ class p3ChatService: public p3Service, public p3Config, public pqiMonitor std::map _lobby_ids ; std::string _default_nick_name ; float _time_shift_average ; - time_t last_lobby_challenge_time ; // prevents bruteforce attack + time_t last_lobby_challenge_time ; // prevents bruteforce attack time_t last_visible_lobby_info_request_time ; // allows to ask for updates bool _should_reset_lobby_counts ; + + RsChatSerialiser *_serializer ; + + // ===========================================================// + // Members related to anonymous distant chat. // + // ===========================================================// + + public: + void connectToTurtleRouter(p3turtle *) ; + + // Creates the invite if the public key of the distant peer is available. + // Om success, stores the invite in the map above, so that we can respond to tunnel requests. + // + bool createDistantChatInvite(const std::string& pgp_id,time_t time_of_validity,TurtleFileHash& hash) ; + bool getDistantChatInviteList(std::vector& invites) ; + bool initiateDistantChatConnexion(const std::string& encrypted_string,std::string& hash,uint32_t& error_code) ; + + virtual bool getDistantChatStatus(const std::string& hash,uint32_t& status,std::string& pgp_id) ; + + private: + struct DistantChatInvite + { + unsigned char aes_key[16] ; + std::string encrypted_radix64_string ; + std::string destination_pgp_id ; + time_t time_of_validity ; + time_t last_hit_time ; + }; + struct DistantChatPeerInfo + { + time_t last_contact ; // used to send keep alive packets + unsigned char aes_key[16] ; // key to encrypt packets + uint32_t status ; // info: do we have a tunnel ? + std::string virtual_peer_id; // given by the turtle router. Identifies the tunnel. + std::string pgp_id ; // pgp id of the peer we're talking to. + }; + + // This map contains the ongoing invites. This is the list where to look to + // handle tunnel requests. + // + std::map _distant_chat_invites ; + + // This maps contains the current peers to talk to with distant chat. + // + std::map _distant_chat_peers ; + + // Overloaded from RsTurtleClientService + + virtual bool handleTunnelRequest(const std::string& hash,const std::string& peer_id) ; + virtual void receiveTurtleData(RsTurtleGenericTunnelItem *item,const std::string& hash,const std::string& virtual_peer_id,RsTurtleGenericTunnelItem::Direction direction) ; + void addVirtualPeer(const TurtleFileHash&, const TurtleVirtualPeerId&,RsTurtleGenericTunnelItem::Direction dir) ; + void removeVirtualPeer(const TurtleFileHash&, const TurtleVirtualPeerId&) ; + + // Utility functions + + void cleanDistantChatInvites() ; + void sendTurtleData(RsChatItem *) ; + void sendPrivateChatItem(RsChatItem *) ; + + p3turtle *mTurtle ; }; class p3ChatService::StateStringInfo diff --git a/libretroshare/src/services/p3msgservice.cc b/libretroshare/src/services/p3msgservice.cc index 0ae6daac3..cb945a4c2 100644 --- a/libretroshare/src/services/p3msgservice.cc +++ b/libretroshare/src/services/p3msgservice.cc @@ -25,23 +25,34 @@ #include "retroshare/rsiface.h" +#include "retroshare/rspeers.h" #include "pqi/pqibin.h" #include "pqi/pqiarchive.h" #include "pqi/p3linkmgr.h" +#include "pqi/authgpg.h" #include "services/p3msgservice.h" +#include "pgp/pgpkeyutil.h" #include "pqi/pqinotify.h" #include "util/rsdebug.h" #include "util/rsdir.h" #include "util/rsstring.h" +#include "util/radix64.h" +#include "util/rsrandom.h" #include #include +//#define DEBUG_DISTANT_MSG + const int msgservicezone = 54319; +static const uint32_t RS_DISTANT_MSG_STATUS_TUNNEL_OK = 0x0001 ; +static const uint32_t RS_DISTANT_MSG_STATUS_TUNNEL_DN = 0x0000 ; +static const uint32_t DISTANT_MSG_HASH_SIZE = 20 ; + /* Another little hack ..... unique message Ids * will be handled in this class..... * These are unique within this run of the server, @@ -58,7 +69,8 @@ p3MsgService::p3MsgService(p3LinkMgr *lm) :p3Service(RS_SERVICE_TYPE_MSG), p3Config(CONFIG_TYPE_MSGS), mLinkMgr(lm), mMsgMtx("p3MsgService"), mMsgUniqueId(time(NULL)) { - addSerialType(new RsMsgSerialiser()); + _serialiser = new RsMsgSerialiser(); + addSerialType(_serialiser); /* Initialize standard tag types */ if(lm) @@ -81,6 +93,15 @@ int p3MsgService::tick() */ incomingMsgs(); + + static time_t last_management_time = 0 ; + time_t now = time(NULL) ; + + if(now > last_management_time + 5) + { + manageDistantPeers() ; + last_management_time = now ; + } //checkOutgoingMessages(); return 0; @@ -107,7 +128,7 @@ void p3MsgService::processMsg(RsMsgItem *mi, bool incoming) { /* from a peer */ - mi->msgFlags &= RS_MSG_FLAGS_SYSTEM; // remove flags + mi->msgFlags &= (RS_MSG_FLAGS_ENCRYPTED | RS_MSG_FLAGS_SYSTEM); // remove flags except those mi->msgFlags |= RS_MSG_FLAGS_NEW; pqiNotify *notify = getPqiNotify(); @@ -187,22 +208,27 @@ int p3MsgService::incomingMsgs() { RsMsgItem *mi; int i = 0; - bool changed = false ; while((mi = (RsMsgItem *) recvItem()) != NULL) { - changed = true ; - ++i; + handleIncomingItem(mi) ; + ++i ; + } - if(checkAndRebuildPartialMessage(mi)) // only returns true when a msg is complete. - { - processMsg(mi, true); - } + return i; +} + +void p3MsgService::handleIncomingItem(RsMsgItem *mi) +{ + bool changed = false ; + + if(checkAndRebuildPartialMessage(mi)) // only returns true when a msg is complete. + { + processMsg(mi, true); + changed = true ; } if(changed) rsicontrol->getNotify().notifyListChange(NOTIFY_LIST_MESSAGELIST,NOTIFY_TYPE_MOD); - - return 1; } void p3MsgService::statusChange(const std::list &/*plist*/) @@ -233,10 +259,18 @@ void p3MsgService::checkSizeAndSendMessage(RsMsgItem *msg) // Indicate that the message is to be continued. // item->msgFlags |= RS_MSG_FLAGS_PARTIAL ; - sendItem(item) ; + + if(msg->msgFlags & RS_MSG_FLAGS_DISTANT) + sendPrivateMsgItem(msg) ; + else + sendItem(item) ; } std::cerr << " Chopped off msg of size " << msg->message.size() << std::endl; - sendItem(msg) ; + + if(msg->msgFlags & RS_MSG_FLAGS_DISTANT) + sendPrivateMsgItem(msg) ; + else + sendItem(msg) ; } int p3MsgService::checkOutgoingMessages() @@ -247,6 +281,7 @@ int p3MsgService::checkOutgoingMessages() */ bool changed = false ; + std::list output_queue ; { const std::string ownId = mLinkMgr->getOwnId(); @@ -264,18 +299,8 @@ int p3MsgService::checkOutgoingMessages() /* find the certificate */ std::string pid = mit->second->PeerId(); - bool toSend = false; - if (mLinkMgr->isOnline(pid)) - { - toSend = true; - } - else if (pid == ownId) /* FEEDBACK Msg to Ourselves */ - { - toSend = true; - } - - if (toSend) + if(mit->second->msgFlags & RS_MSG_FLAGS_DISTANT || mLinkMgr->isOnline(pid) || pid == ownId) /* FEEDBACK Msg to Ourselves */ { /* send msg */ pqioutput(PQL_DEBUG_BASIC, msgservicezone, @@ -283,7 +308,7 @@ int p3MsgService::checkOutgoingMessages() /* remove the pending flag */ (mit->second)->msgFlags &= ~RS_MSG_FLAGS_PENDING; - checkSizeAndSendMessage(mit->second) ; + output_queue.push_back(mit->second) ; toErase.push_back(mit->first); changed = true ; @@ -317,6 +342,9 @@ int p3MsgService::checkOutgoingMessages() } } + for(std::list::const_iterator it(output_queue.begin());it!=output_queue.end();++it) + checkSizeAndSendMessage(*it) ; + if(changed) rsicontrol->getNotify().notifyListChange(NOTIFY_LIST_MESSAGELIST,NOTIFY_TYPE_MOD); @@ -357,6 +385,14 @@ bool p3MsgService::saveList(bool& cleanup, std::list& itemList) for(mit4 = mParentId.begin(); mit4 != mParentId.end(); mit4++) itemList.push_back(mit4->second); + for(std::map::const_iterator it(_messenging_invites.begin());it!=_messenging_invites.end();++it) + { + RsPublicMsgInviteConfigItem *item = new RsPublicMsgInviteConfigItem ; + item->hash = it->first ; + item->time_stamp = it->second.time_of_validity ; + + itemList.push_back(item) ; + } return true; } @@ -421,6 +457,7 @@ bool p3MsgService::loadList(std::list& load) RsMsgTags* mti; RsMsgSrcId* msi; RsMsgParentId* msp; + RsPublicMsgInviteConfigItem* msv; std::list items; std::list::iterator it; @@ -442,18 +479,18 @@ bool p3MsgService::loadList(std::list& load) items.push_back(mitem); } else if(NULL != (mtt = dynamic_cast(*it))) - { - // delete standard tags as they are now save in config - if(mTags.end() == (tagIt = mTags.find(mtt->tagId))) - { - mTags.insert(std::pair(mtt->tagId, mtt)); - } - else - { - delete mTags[mtt->tagId]; - mTags.erase(tagIt); - mTags.insert(std::pair(mtt->tagId, mtt)); - } + { + // delete standard tags as they are now save in config + if(mTags.end() == (tagIt = mTags.find(mtt->tagId))) + { + mTags.insert(std::pair(mtt->tagId, mtt)); + } + else + { + delete mTags[mtt->tagId]; + mTags.erase(tagIt); + mTags.insert(std::pair(mtt->tagId, mtt)); + } } else if(NULL != (mti = dynamic_cast(*it))) @@ -469,6 +506,10 @@ bool p3MsgService::loadList(std::list& load) { mParentId.insert(std::pair(msp->msgId, msp)); } + else if(NULL != (msv = dynamic_cast(*it))) + { + _messenging_invites[msv->hash].time_of_validity = msv->time_stamp ; + } } // sort items into lists @@ -1357,6 +1398,10 @@ void p3MsgService::initRsMI(RsMsgItem *msg, MessageInfo &mi) { mi.msgflags |= RS_MSG_NEW; } + + if (msg->msgFlags & RS_MSG_FLAGS_ENCRYPTED) + mi.msgflags |= RS_MSG_ENCRYPTED ; + if (msg->msgFlags & RS_MSG_FLAGS_TRASH) { mi.msgflags |= RS_MSG_TRASH; @@ -1442,6 +1487,9 @@ void p3MsgService::initRsMIS(RsMsgItem *msg, MsgInfoSummary &mis) { mis.msgflags = 0; + if (msg->msgFlags & RS_MSG_FLAGS_ENCRYPTED) + mis.msgflags |= RS_MSG_ENCRYPTED ; + /* translate flags, if we sent it... outgoing */ if ((msg->msgFlags & RS_MSG_FLAGS_OUTGOING) /*|| (msg->PeerId() == mLinkMgr->getOwnId())*/) @@ -1513,7 +1561,8 @@ RsMsgItem *p3MsgService::initMIRsMsg(MessageInfo &info, const std::string &to) msg -> recvTime = 0; msg -> subject = info.title; - msg -> message = info.msg; + + msg -> message = info.msg; std::list::iterator pit; for(pit = info.msgto.begin(); pit != info.msgto.end(); pit++) @@ -1538,6 +1587,10 @@ RsMsgItem *p3MsgService::initMIRsMsg(MessageInfo &info, const std::string &to) msg -> attachment.title = info.attach_title; msg -> attachment.comment = info.attach_comment; + RsPeerDetails details ; + if(!rsPeers->getPeerDetails(to,details)) + msg->msgFlags |= RS_MSG_FLAGS_DISTANT; + std::list::iterator it; for(it = info.files.begin(); it != info.files.end(); it++) { @@ -1550,15 +1603,428 @@ RsMsgItem *p3MsgService::initMIRsMsg(MessageInfo &info, const std::string &to) /* translate flags from outside */ if (info.msgflags & RS_MSG_USER_REQUEST) - { msg->msgFlags |= RS_MSG_FLAGS_USER_REQUEST; - } - if (info.msgflags & RS_MSG_FRIEND_RECOMMENDATION) - { - msg->msgFlags |= RS_MSG_FLAGS_FRIEND_RECOMMENDATION; - } - //std::cerr << "p3MsgService::initMIRsMsg()" << std::endl; + if (info.msgflags & RS_MSG_FRIEND_RECOMMENDATION) + msg->msgFlags |= RS_MSG_FLAGS_FRIEND_RECOMMENDATION; + + // See if we need to encrypt this message. If so, we replace the msg text + // by the whole message serialized and binary encrypted, so as to obfuscate + // all its content. + // + bool enc_ok = false ; + + if(info.encryption_keys.find(to) != info.encryption_keys.end()) + encryptMessage(info.encryption_keys[to],msg) ; + + //std::cerr << "p3MsgService::initMIRsMsg()" << std::endl; //msg->print(std::cerr); return msg; } + +bool p3MsgService::encryptMessage(const std::string& pgp_id,RsMsgItem *item) +{ +#ifdef DEBUG_DISTANT_MSG + std::cerr << "Encrypting message with public key " << pgp_id << " in place." << std::endl; +#endif + + // 1 - serialise the whole message item into a binary chunk. + // + uint32_t rssize = _serialiser->size(item) ; + unsigned char *data = new unsigned char[rssize] ; + + if(!_serialiser->serialise(item,data,&rssize)) + { + std::cerr << "(EE) p3MsgService::sendTurtleData(): Serialization error." << std::endl; + delete[] data ; + return false; + } + + // 2 - pgp-encrypt the chunk with the user-supplied public key. + // + uint32_t encrypted_size = rssize + 1000 ; + unsigned char *encrypted_data = new unsigned char[encrypted_size] ; + + if(!AuthGPG::getAuthGPG()->encryptDataBin(pgp_id,data,rssize,encrypted_data,&encrypted_size)) + { + delete[] data ; + delete[] encrypted_data ; + std::cerr << "Encryption failed!" << std::endl; + return false; + } + delete[] data ; + + // Now turn the binary encrypted chunk into a readable radix string. + // + std::string armoured_data ; + Radix64::encode((char *)encrypted_data,encrypted_size,armoured_data) ; + delete[] encrypted_data ; + + std::wstring encrypted_msg ; + + if(!librs::util::ConvertUtf8ToUtf16(armoured_data,encrypted_msg)) + return false; + + // wipe the item clean and replace the message by the encrypted data. + + item->message = encrypted_msg ; + item->subject = L"" ; + item->msgcc.ids.clear() ; + item->msgbcc.ids.clear() ; + item->msgto.ids.clear() ; + item->msgFlags |= RS_MSG_FLAGS_ENCRYPTED ; + item->attachment.TlvClear() ; + + return true ; +} + +bool p3MsgService::decryptMessage(const std::string& mId) +{ + uint32_t msgId = atoi(mId.c_str()); + std::string encrypted_string ; + + { + RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/ + + std::map::iterator mit = imsg.find(msgId); + + if(mit == imsg.end() || !librs::util::ConvertUtf16ToUtf8(mit->second->message,encrypted_string)) + return false; + } + + char *encrypted_data ; + size_t encrypted_size ; + + Radix64::decode(encrypted_string,encrypted_data,encrypted_size) ; + + uint32_t decrypted_size = encrypted_size + 500 ; + unsigned char *decrypted_data = new unsigned char[decrypted_size] ; + + if(!AuthGPG::getAuthGPG()->decryptDataBin(encrypted_data,encrypted_size,decrypted_data,&decrypted_size)) + { + delete[] encrypted_data ; + delete[] decrypted_data ; + std::cerr << "decryption failed!" << std::endl; + return false; + } + + RsMsgItem *item = dynamic_cast(_serialiser->deserialise(decrypted_data,&decrypted_size)) ; + + if(item == NULL) + return false ; + + { + RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/ + *imsg[msgId] = *item ; + } + delete item ; + + IndicateConfigChanged() ; + + return true ; +} + +void p3MsgService::connectToTurtleRouter(p3turtle *pt) +{ + mTurtle = pt ; + pt->registerTunnelService(this) ; +} +bool p3MsgService::createDistantOfflineMessengingInvite(time_t time_of_validity,TurtleFileHash& hash) +{ + unsigned char hash_bytes[DISTANT_MSG_HASH_SIZE] ; + RSRandom::random_bytes( hash_bytes, DISTANT_MSG_HASH_SIZE) ; + + hash = t_RsGenericIdType(hash_bytes).toStdString(false) ; + + DistantMessengingInvite invite ; + invite.time_of_validity = time_of_validity + time(NULL); + + { + RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/ + _messenging_invites[hash] = invite ; + } + IndicateConfigChanged() ; + + return true ; +} +bool p3MsgService::getDistantOfflineMessengingInvites(std::vector& invites) +{ + RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/ + + for(std::map::const_iterator it(_messenging_invites.begin());it!=_messenging_invites.end();++it) + { + DistantOfflineMessengingInvite invite ; + invite.hash = it->first ; + invite.issuer_pgp_id = AuthGPG::getAuthGPG()->getGPGOwnId() ; + invite.time_of_validity = it->second.time_of_validity ; + + invites.push_back(invite) ; + +#ifdef DEBUG_DISTANT_MSG + std::cerr << " adding invite with hash " << invite.hash << std::endl; +#endif + } + + return true ; +} +bool p3MsgService::handleTunnelRequest(const std::string& hash,const std::string& peer_id) +{ +#ifdef DEBUG_DISTANT_MSG + std::cerr << "p3MsgService::handleTunnelRequest: received TR for hash " << hash << std::endl; +#endif + + RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/ + std::map::const_iterator it = _messenging_invites.find(hash) ; + +#ifdef DEBUG_DISTANT_MSG + if(it != _messenging_invites.end()) + std::cerr << "Responding OK!" << std::endl; +#endif + + return it != _messenging_invites.end() ; +} + +void p3MsgService::manageDistantPeers() +{ + // now possibly flush pending messages + +#ifdef DEBUG_DISTANT_MSG + std::cerr << "p3MsgService::manageDistantPeers()" << std::endl; +#endif + + std::vector > to_send ; + + { + RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/ + for(std::map::iterator it(_messenging_contacts.begin());it!=_messenging_contacts.end();++it) + if(it->second.status == RS_DISTANT_MSG_STATUS_TUNNEL_OK) + { + for(uint32_t i=0;isecond.pending_messages.size();++i) + to_send.push_back(std::pair(it->first,it->second.pending_messages[i])) ; + + it->second.pending_messages.clear() ; + } + } + + for(uint32_t i=0;imsgId << std::endl; +#endif + sendTurtleData(to_send[i].first,to_send[i].second) ; + } + + time_t now = time(NULL) ; + { + RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/ + + // clean dead invites. + // + for(std::map::iterator it(_messenging_invites.begin());it!=_messenging_invites.end();) + if(it->second.time_of_validity < now) + { +#ifdef DEBUG_DISTANT_MSG + std::cerr << " Removing outdated invite " << it->second.time_of_validity << ", hash=" << it->first << std::endl; +#endif + std::map::iterator tmp(it) ; + ++tmp ; + _messenging_invites.erase(it) ; + it = tmp ; + } + else + ++it ; + + // clean dead contacts. + // + for(std::map::iterator it(_messenging_contacts.begin());it!=_messenging_contacts.end();) + if(it->second.pending_messages.empty() && it->second.status == RS_DISTANT_MSG_STATUS_TUNNEL_DN) + { +#ifdef DEBUG_DISTANT_MSG + std::cerr << " Removing dead contact with no pending msgs and dead tunnel. hash=" << it->first << std::endl; +#endif + std::map::iterator tmp(it) ; + ++tmp ; + _messenging_contacts.erase(it) ; + it = tmp ; + } + else + ++it ; + } +} + +void p3MsgService::addVirtualPeer(const TurtleFileHash& hash, const TurtleVirtualPeerId& vpid,RsTurtleGenericTunnelItem::Direction dir) +{ + RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/ + // A new tunnel has been created. We need to flush pending messages for the corresponding peer. + + //std::map::const_iterator it = _messenging_contacts.find(hash) ; + + DistantMessengingContact& contact(_messenging_contacts[hash]) ; // possibly creates it. + + contact.virtual_peer_id = vpid ; + contact.last_hit_time = time(NULL) ; + contact.status = RS_DISTANT_MSG_STATUS_TUNNEL_OK ; + +#ifdef DEBUG_DISTANT_MSG + std::cerr << "p3MsgService::addVirtualPeer(): adding virtual peer " << vpid << " for hash " << hash << std::endl; +#endif +} +void p3MsgService::removeVirtualPeer(const TurtleFileHash& hash, const TurtleVirtualPeerId& vpid) +{ + RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/ + // A new tunnel has been created. We need to flush pending messages for the corresponding peer. + + //std::map::const_iterator it = _messenging_contacts.find(hash) ; + + DistantMessengingContact& contact(_messenging_contacts[hash]) ; // possibly creates it. + + contact.status = RS_DISTANT_MSG_STATUS_TUNNEL_DN ; + contact.virtual_peer_id.clear() ; +} +#ifdef DEBUG_DISTANT_MSG +static void printBinaryData(void *data,uint32_t size) +{ + static const char outl[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' } ; + + for(uint32_t j = 0; j < size; j++) + { + std::cerr << outl[ ( ((uint8_t*)data)[j]>>4) ] ; + std::cerr << outl[ ((uint8_t*)data)[j] & 0xf ] ; + } +} +#endif + +void p3MsgService::sendTurtleData(const std::string& hash,RsMsgItem *msgitem) +{ + // The item is serialized and turned into a generic turtle item. + + uint32_t rssize = _serialiser->size(msgitem) ; + unsigned char *data = new unsigned char[rssize] ; + + if(!_serialiser->serialise(msgitem,data,&rssize)) + { + std::cerr << "(EE) p3MsgService::sendTurtleData(): Serialization error." << std::endl; + delete[] data ; + return ; + } + + RsTurtleGenericDataItem *item = new RsTurtleGenericDataItem ; + item->data_bytes = malloc(rssize) ; + item->data_size = rssize ; + memcpy(item->data_bytes,data,rssize) ; + + delete[] data ; + +#ifdef DEBUG_DISTANT_MSG + printBinaryData(item->data_bytes,item->data_size) ; + std::cerr << std::endl; +#endif + + // do we have a working tunnel for that hash ? + // If not, put on the contact's waiting list. + + std::string virtual_peer_id ; + { + RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/ + std::map::const_iterator it = _messenging_contacts.find(hash) ; + + if(it == _messenging_contacts.end()) + { + std::cerr << "(EE) p3MsgService::sendTurtleData(): Can't find hash " << hash << " in recorded contact list." << std::endl; + delete[] data ; + return ; + } + + if(!it->second.status == RS_DISTANT_MSG_STATUS_TUNNEL_OK) + { + std::cerr << "p3MsgService::sendTurtleData(): tunnel is not ok. Putting items on waiting list." << std::endl; + return ; + } + virtual_peer_id = it->second.virtual_peer_id ; + } +#ifdef DEBUG_DISTANT_MSG + std::cerr << "p3MsgService::sendTurtleData(): Sending through virtual peer: " << virtual_peer_id << std::endl; + std::cerr << " item->data_size = " << item->data_size << std::endl; + std::cerr << " data = " ; +#endif + + mTurtle->sendTurtleData(virtual_peer_id,item) ; +} + +void p3MsgService::receiveTurtleData(RsTurtleGenericTunnelItem *gitem,const std::string& hash, + const std::string& virtual_peer_id,RsTurtleGenericTunnelItem::Direction direction) +{ + RsTurtleGenericDataItem *item = dynamic_cast(gitem) ; + + if(item == NULL) + { + std::cerr << "(EE) p3MsgService::receiveTurtleData(): item is not a data item. That is an error." << std::endl; + return ; + } +#ifdef DEBUG_DISTANT_MSG + std::cerr << "p3MsgService::sendTurtleData(): Receiving through virtual peer: " << virtual_peer_id << std::endl; + std::cerr << " gitem->data_size = " << item->data_size << std::endl; + std::cerr << " data = " ; + printBinaryData(item->data_bytes,item->data_size) ; + std::cerr << std::endl; +#endif + + { + RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/ + std::map::iterator it = _messenging_contacts.find(hash) ; + + if(it == _messenging_contacts.end()) + { + std::cerr << "(EE) p3MsgService::sendTurtleData(): Can't find hash " << hash << " in recorded contact list." << std::endl; + return ; + } + + it->second.status = RS_DISTANT_MSG_STATUS_TUNNEL_OK ; + it->second.last_hit_time = time(NULL) ; + } + + RsItem *itm = _serialiser->deserialise(item->data_bytes,&item->data_size) ; + + RsMsgItem *mitm = dynamic_cast(itm) ; + + if(mitm != NULL) + { + mitm->PeerId(hash) ; + handleIncomingItem(mitm) ; + } + else + { + std::cerr << "(EE) p3MsgService::receiveTurtleData(): received item is not a RsMsgItem!!" << std::endl; + delete itm ; + } +} + +void p3MsgService::sendPrivateMsgItem(RsMsgItem *msgitem) +{ +#ifdef DEBUG_DISTANT_MSG + std::cerr << "p3MsgService::sendDistanteMsgItem(): sending distant msg item to peer " << msgitem->PeerId() << std::endl; + std::cerr << " asking for tunnels" << std::endl; + std::cerr << " recording msg info" << std::endl; +#endif + const std::string& hash = msgitem->PeerId() ; + rsTurtle->monitorTunnels(hash,this) ; // create a tunnel for it, and put the msg on the waiting list. + + { + RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/ + + // allocate a new contact. If it does not exist, set its tunnel state to DN + // + std::map::iterator it = _messenging_contacts.find(hash) ; + + DistantMessengingContact& contact( _messenging_contacts[hash] ) ; + + if(it == _messenging_contacts.end()) + it->second.status = RS_DISTANT_MSG_STATUS_TUNNEL_DN ; + + contact.pending_messages.push_back(msgitem) ; // record the msg to be sent. + } +} + + + + diff --git a/libretroshare/src/services/p3msgservice.h b/libretroshare/src/services/p3msgservice.h index 64d76827c..2f6592fe7 100644 --- a/libretroshare/src/services/p3msgservice.h +++ b/libretroshare/src/services/p3msgservice.h @@ -42,10 +42,12 @@ #include "services/p3service.h" #include "serialiser/rsmsgitems.h" #include "util/rsthreads.h" +#include "turtle/p3turtle.h" +#include "turtle/turtleclientservice.h" class p3LinkMgr; -class p3MsgService: public p3Service, public p3Config, public pqiMonitor +class p3MsgService: public p3Service, public p3Config, public pqiMonitor, public RsTurtleClientService { public: p3MsgService(p3LinkMgr *lm); @@ -55,6 +57,7 @@ bool getMessageSummaries(std::list &msgList); bool getMessage(const std::string &mid, MessageInfo &msg); void getMessageCount(unsigned int *pnInbox, unsigned int *pnInboxNew, unsigned int *pnOutbox, unsigned int *pnDraftbox, unsigned int *pnSentbox, unsigned int *pnTrashbox); +bool decryptMessage(const std::string& mid) ; bool removeMsgId(const std::string &mid); bool markMsgIdRead(const std::string &mid, bool bUnreadByUser); bool setMsgFlag(const std::string &mid, uint32_t flag, uint32_t mask); @@ -97,7 +100,51 @@ virtual void statusChange(const std::list &plist); int checkOutgoingMessages(); /*** Overloaded from pqiMonitor ***/ + /*** overloaded from p3turtle ***/ + + void connectToTurtleRouter(p3turtle *) ; + + struct DistantMessengingInvite + { + time_t time_of_validity ; + }; + struct DistantMessengingContact + { + time_t last_hit_time ; + std::string virtual_peer_id ; + uint32_t status ; + std::vector pending_messages ; + }; + + bool createDistantOfflineMessengingInvite(time_t time_of_validity,TurtleFileHash& hash) ; + bool getDistantOfflineMessengingInvites(std::vector& invites) ; + void sendPrivateMsgItem(RsMsgItem *) ; + private: + // This maps contains the current invitations to respond to. + // + std::map _messenging_invites ; + + // This contains the ongoing tunnel handling contacts. + // + std::map _messenging_contacts ; + + // Overloaded from RsTurtleClientService + + virtual bool handleTunnelRequest(const std::string& hash,const std::string& peer_id) ; + virtual void receiveTurtleData(RsTurtleGenericTunnelItem *item,const std::string& hash,const std::string& virtual_peer_id,RsTurtleGenericTunnelItem::Direction direction) ; + void addVirtualPeer(const TurtleFileHash&, const TurtleVirtualPeerId&,RsTurtleGenericTunnelItem::Direction dir) ; + void removeVirtualPeer(const TurtleFileHash&, const TurtleVirtualPeerId&) ; + + // Utility functions + + bool encryptMessage(const std::string& pgp_id,RsMsgItem *msg) ; + + void manageDistantPeers() ; + void sendTurtleData(const std::string& hash,RsMsgItem *) ; + void handleIncomingItem(RsMsgItem *) ; + + p3turtle *mTurtle ; uint32_t getNewUniqueMsgId(); int sendMessage(RsMsgItem *item); @@ -118,6 +165,7 @@ void initStandardTagTypes(); /* Mutex Required for stuff below */ RsMutex mMsgMtx; + RsMsgSerialiser *_serialiser ; /* stored list of messages */ std::map imsg; diff --git a/libretroshare/src/tests/network_simulator/MonitoredTurtle.h b/libretroshare/src/tests/network_simulator/MonitoredTurtle.h index d9d59daa3..f7895d5f3 100644 --- a/libretroshare/src/tests/network_simulator/MonitoredTurtle.h +++ b/libretroshare/src/tests/network_simulator/MonitoredTurtle.h @@ -4,7 +4,7 @@ class MonitoredTurtleRouter: public p3turtle { public: MonitoredTurtleRouter(p3LinkMgr *lmgr,ftServer *fts) - : p3turtle(lmgr,fts) + : p3turtle(lmgr) { } diff --git a/libretroshare/src/tests/network_simulator/Network.cpp b/libretroshare/src/tests/network_simulator/Network.cpp index 6b04be31d..2dd1a928a 100644 --- a/libretroshare/src/tests/network_simulator/Network.cpp +++ b/libretroshare/src/tests/network_simulator/Network.cpp @@ -172,7 +172,7 @@ void PeerNode::provideFileHash(const std::string& hash) void PeerNode::manageFileHash(const std::string& hash) { _managed_hashes.insert(hash) ; - _turtle->monitorFileTunnels("file 1",hash,10000) ; + _turtle->monitorTunnels(hash,_ftserver) ; } void PeerNode::getTrafficInfo(NodeTrafficInfo& info) diff --git a/libretroshare/src/tests/network_simulator/Network.h b/libretroshare/src/tests/network_simulator/Network.h index 248ac0e44..e3805038f 100644 --- a/libretroshare/src/tests/network_simulator/Network.h +++ b/libretroshare/src/tests/network_simulator/Network.h @@ -47,6 +47,7 @@ class PeerNode private: p3ServiceServer *_service_server ; MonitoredTurtleRouter *_turtle ; + ftServer *_ftserver ; std::string _id ; std::set _provided_hashes ; diff --git a/libretroshare/src/tests/util/Makefile b/libretroshare/src/tests/util/Makefile index f4fb514b6..9be844a06 100644 --- a/libretroshare/src/tests/util/Makefile +++ b/libretroshare/src/tests/util/Makefile @@ -9,8 +9,8 @@ OPS_TOP_DIR = ../../../../openpgpsdk/src include $(RS_TOP_DIR)/tests/scripts/config.mk ############################################################### -TESTOBJ = dirtest.o sha1_test.o -TESTS = dirtest sha1_test +TESTOBJ = dirtest.o sha1_test.o aes_test.o dchat_decrypt.o +TESTS = dirtest sha1_test aes_test dchat_decrypt all: tests @@ -18,6 +18,10 @@ sha1_test: sha1_test.o $(CC) $(CFLAGS) -o sha1_test sha1_test.o $(LIBS) dirtest: dirtest.o $(CC) $(CFLAGS) -o dirtest dirtest.o $(LIBS) +dirtest: aes_test.o + $(CC) $(CFLAGS) -o aes_test aes_test.o $(LIBS) +dchat_decrypt: dchat_decrypt.o + $(CC) $(CFLAGS) -o dchat_decrypt dchat_decrypt.o $(LIBS) ############################################################### include $(RS_TOP_DIR)/tests/scripts/rules.mk diff --git a/libretroshare/src/tests/util/aes_test.cc b/libretroshare/src/tests/util/aes_test.cc new file mode 100644 index 000000000..f7e2531fd --- /dev/null +++ b/libretroshare/src/tests/util/aes_test.cc @@ -0,0 +1,115 @@ + +/* + * "$Id: dirtest.cc,v 1.1 2007-02-19 20:08:30 rmf24 Exp $" + * + * RetroShare C++ Interface. + * + * Copyright 2012-2012 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". + * + */ + + + +#include "util/rsaes.h" +#include "util/utest.h" +#include + +#include +#include +#include +#include + +void printHelp(int argc,char *argv[]) +{ + std::cerr << argv[0] << ": tests AES encryption/decryption functions." << std::endl; + std::cerr << "Usage: " << argv[0] << std::endl ; +} + +void printHex(unsigned char *data,uint32_t length) +{ + static const char outh[16] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' } ; + static const char outl[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' } ; + + for(uint32_t j = 0; j < length; j++) + { + std::cerr << outh[ (data[j]>>4) ] ; + std::cerr << outh[ data[j] & 0xf ] ; + } +} + + +INITTEST() ; + +int main(int argc,char *argv[]) +{ + std::string inputfile ; + argstream as(argc,argv) ; + + as >> help() ; + + as.defaultErrorHandling() ; + + std::cerr << "Testing AES crypt" << std::endl; + + std::string source_string = "This is a very secret string, but ultimately it will always be decyphered" ; + std::cerr << "Input string: length=" << source_string.length() << ", s=\"" << source_string << "\"" << std::endl; + + unsigned char key_data[16] ; + unsigned char salt[8] ; + + for(int i=0;i<16;++i) + key_data[i] = lrand48() & 0xff ; + + std::cerr << "Key: " ; printHex(key_data,16); + std::cerr << std::endl; + + for(int i=5;igetController() ; - _random_bias = RSRandom::random_u32() ; + _serialiser = new RsTurtleSerialiser() ; - addSerialType(new RsTurtleSerialiser()); + addSerialType(_serialiser); _last_clean_time = 0 ; _last_tunnel_management_time = 0 ; @@ -120,7 +118,6 @@ p3turtle::p3turtle(p3LinkMgr *lm,ftServer *fs) _last_tunnel_speed_estimate_time = 0 ; _traffic_info.reset() ; - _sharing_strategy = SHARE_ENTIRE_NETWORK ; _max_tr_up_rate = MAX_TR_FORWARD_PER_SEC ; } @@ -261,31 +258,6 @@ int p3turtle::tick() // -----------------------------------------------------------------------------------// // -#ifdef TO_REMOVE -// This method handles peer connexion/deconnexion -// If A connects, new tunnels should be initiated from A -// If A disconnects, the tunnels passed through A should be closed. -// -void p3turtle::statusChange(const std::list &plist) // derived from pqiMonitor -{ - RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ - - // We actually do not shut down tunnels when peers get down: Tunnels that - // are not working properly get automatically removed after some time. - - // save the list of active peers. This is useful for notifying the ftContoller - _online_peers = plist ; - - std::cerr << "p3turtle: status change triggered. Saving list of " << plist.size() << " peers." << std::endl ; - - /* if any have switched to 'connected' then we force digging new tunnels */ - - for(std::list::const_iterator pit = plist.begin(); pit != plist.end(); pit++) - if ((pit->state & RS_PEER_S_FRIEND) && (pit->actions & RS_PEER_CONNECTED)) - _force_digg_new_tunnels = true ; -} -#endif - // adds a virtual peer to the list that is communicated ot ftController. // void p3turtle::locked_addDistantPeer(const TurtleFileHash&,TurtleTunnelId tid) @@ -349,7 +321,7 @@ void p3turtle::manageTunnels() // digg new tunnels if no tunnels are available and force digg new tunnels at regular (large) interval // - for(std::map::const_iterator it(_incoming_file_hashes.begin());it!=_incoming_file_hashes.end();++it) + for(std::map::const_iterator it(_incoming_file_hashes.begin());it!=_incoming_file_hashes.end();++it) { // get total tunnel speed. // @@ -418,7 +390,7 @@ void p3turtle::autoWash() for(unsigned int i=0;i<_hashes_to_remove.size();++i) { - std::map::iterator it(_incoming_file_hashes.find(_hashes_to_remove[i])) ; + std::map::iterator it(_incoming_file_hashes.find(_hashes_to_remove[i])) ; if(it == _incoming_file_hashes.end()) { @@ -520,11 +492,25 @@ void p3turtle::autoWash() // File hashes can only be removed by calling the 'stopMonitoringFileTunnels()' command. - // All calls to _ft_controller are done off-mutex, to avoir cross-lock - if(_ft_controller != NULL) - for(uint32_t i=0;iremoveFileSource(peers_to_remove[i].first,peers_to_remove[i].second) ; + for(uint32_t i=0;i::iterator it(_incoming_file_hashes.find(peers_to_remove[i].first)) ; + + if(it != _incoming_file_hashes.end()) + service = it->second.service ; + else + std::cerr << "p3turtle::autowash(): ERROR. No service associated to hash " << peers_to_remove[i].first << ": this is super weird." << std::endl; + } + // All calls to services are done off-mutex, to avoir cross-lock + // + if(service != NULL) + service->removeVirtualPeer(peers_to_remove[i].first,peers_to_remove[i].second) ; + } } void p3turtle::locked_closeTunnel(TurtleTunnelId tid,std::vector >& sources_to_remove) @@ -567,7 +553,7 @@ void p3turtle::locked_closeTunnel(TurtleTunnelId tid,std::vector::iterator it(_incoming_file_hashes.find(hash)) ; + std::map::iterator it(_incoming_file_hashes.find(hash)) ; if(it != _incoming_file_hashes.end()) { @@ -592,7 +578,7 @@ void p3turtle::locked_closeTunnel(TurtleTunnelId tid,std::vector::iterator itHash = _outgoing_file_hashes.find(it->second.hash); + std::map::iterator itHash = _outgoing_file_hashes.find(it->second.hash); if(itHash != _outgoing_file_hashes.end()) _outgoing_file_hashes.erase(itHash) ; } @@ -600,7 +586,7 @@ void p3turtle::locked_closeTunnel(TurtleTunnelId tid,std::vector(item)) ; break ; + default: std::cerr << "p3turtle::handleIncoming: Unknown packet subtype " << item->PacketSubType() << std::endl ; } @@ -836,53 +823,47 @@ void p3turtle::handleSearchRequest(RsTurtleSearchRequestItem *item) #ifdef P3TURTLE_DEBUG std::cerr << " Request not from us. Performing local search" << std::endl ; #endif - if(_sharing_strategy != SHARE_FRIENDS_ONLY || item->depth < 2) + + std::list 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()) { - std::list result ; + // 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 ; - 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()) + if(res_item == NULL) { - // 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 ; + res_item = new RsTurtleSearchResultItem ; + item_size = 0 ; - 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()) ; - 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()) ; + item_size += 8 /* size */ + result.front().hash.size() + result.front().name.size() ; + result.pop_front() ; - item_size += 8 /* size */ + result.front().hash.size() + result.front().name.size() ; - result.pop_front() ; - - if(item_size > RSTURTLE_MAX_SEARCH_RESPONSE_SIZE || result.empty()) - { + if(item_size > RSTURTLE_MAX_SEARCH_RESPONSE_SIZE || result.empty()) + { #ifdef P3TURTLE_DEBUG - std::cerr << " Sending back chunk of size " << item_size << ", for " << res_item->result.size() << " elements." << std::endl ; + std::cerr << " Sending back chunk of size " << item_size << ", for " << res_item->result.size() << " elements." << std::endl ; #endif - sendItem(res_item) ; - res_item = NULL ; - } + sendItem(res_item) ; + res_item = NULL ; } } -#ifdef P3TURTLE_DEBUG - else - std::cerr << " Rejecting local search because strategy is FRIENDS_ONLY and item depth=" << item->depth << std::endl ; -#endif } // If search depth not too large, also forward this search request to all other peers. @@ -997,7 +978,6 @@ void p3turtle::routeGenericTunnelItem(RsTurtleGenericTunnelItem *item) std::cerr << "p3Turtle: treating generic tunnel item:" << std::endl ; item->print(std::cerr,1) ; #endif - RsTurtleGenericTunnelItem::Direction direction = item->travelingDirection() ; { RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ @@ -1023,9 +1003,16 @@ void p3turtle::routeGenericTunnelItem(RsTurtleGenericTunnelItem *item) tunnel.transfered_bytes += static_cast(item)->serial_size() ; + if(item->PeerId() == tunnel.local_dst) + item->setTravelingDirection(RsTurtleGenericTunnelItem::DIRECTION_CLIENT) ; + else if(item->PeerId() == tunnel.local_src) + item->setTravelingDirection(RsTurtleGenericTunnelItem::DIRECTION_SERVER) ; + else + std::cerr << "(EE) critical error in p3turtle::routeGenericTunnelItem(): item mismatches tunnel src/dst ids." << std::endl; + // Let's figure out whether this packet is for us or not. - if(direction == RsTurtleGenericTunnelItem::DIRECTION_CLIENT && tunnel.local_src != mLinkMgr->getOwnId()) + if(item->PeerId() == tunnel.local_dst && tunnel.local_src != mLinkMgr->getOwnId()) //direction == RsTurtleGenericTunnelItem::DIRECTION_CLIENT && { #ifdef P3TURTLE_DEBUG std::cerr << " Forwarding generic item to peer " << tunnel.local_src << std::endl ; @@ -1034,14 +1021,16 @@ void p3turtle::routeGenericTunnelItem(RsTurtleGenericTunnelItem *item) _traffic_info_buffer.unknown_updn_Bps += static_cast(item)->serial_size() ; - if(dynamic_cast(item) != NULL) - item->setPriorityLevel(QOS_PRIORITY_RS_TURTLE_FORWARD_FILE_DATA) ; + // This has been disabled for compilation reasons. Not sure we actually need it. + // + //if(dynamic_cast(item) != NULL) + // item->setPriorityLevel(QOS_PRIORITY_RS_TURTLE_FORWARD_FILE_DATA) ; sendItem(item) ; return ; } - if(direction == RsTurtleGenericTunnelItem::DIRECTION_SERVER && tunnel.local_dst != mLinkMgr->getOwnId()) + if(item->PeerId() == tunnel.local_src && tunnel.local_dst != mLinkMgr->getOwnId()) //direction == RsTurtleGenericTunnelItem::DIRECTION_SERVER && { #ifdef P3TURTLE_DEBUG std::cerr << " Forwarding generic item to peer " << tunnel.local_dst << std::endl ; @@ -1059,631 +1048,163 @@ void p3turtle::routeGenericTunnelItem(RsTurtleGenericTunnelItem *item) // This is done off-mutex, to avoid various deadlocks // - switch(item->PacketSubType()) - { - case RS_TURTLE_SUBTYPE_FILE_REQUEST: handleRecvFileRequest(dynamic_cast(item)) ; - break ; - - case RS_TURTLE_SUBTYPE_FILE_DATA : handleRecvFileData(dynamic_cast(item)) ; - break ; - - case RS_TURTLE_SUBTYPE_FILE_MAP : handleRecvFileMap(dynamic_cast(item)) ; - break ; - - case RS_TURTLE_SUBTYPE_FILE_MAP_REQUEST: handleRecvFileMapRequest(dynamic_cast(item)) ; - break ; - - case RS_TURTLE_SUBTYPE_FILE_CRC : handleRecvFileCRC32Map(dynamic_cast(item)) ; - break ; - - case RS_TURTLE_SUBTYPE_FILE_CRC_REQUEST: handleRecvFileCRC32MapRequest(dynamic_cast(item)) ; - break ; - - case RS_TURTLE_SUBTYPE_CHUNK_CRC : handleRecvChunkCRC(dynamic_cast(item)) ; - break ; - - case RS_TURTLE_SUBTYPE_CHUNK_CRC_REQUEST: handleRecvChunkCRCRequest(dynamic_cast(item)) ; - break ; - default: - std::cerr << "WARNING: Unknown packet type received: id=" << reinterpret_cast(item->PacketSubType()) << ". Is somebody trying to poison you ?" << std::endl ; -#ifdef P3TURTLE_DEBUG - exit(-1) ; -#endif - } + handleRecvGenericTunnelItem(item) ; delete item ; } -void p3turtle::handleRecvFileRequest(RsTurtleFileRequestItem *item) +void p3turtle::handleRecvGenericTunnelItem(RsTurtleGenericTunnelItem *item) { #ifdef P3TURTLE_DEBUG - std::cerr << "p3Turtle: received file request item:" << std::endl ; + std::cerr << "p3Turtle: received Generic tunnel item:" << std::endl ; item->print(std::cerr,1) ; #endif - // This is a new request. Let's add it to the request map, and forward it to - // open peers. + std::string hash ; + std::string vpid ; + RsTurtleClientService *service ; - TurtleVirtualPeerId vpid ; - uint64_t size ; - TurtleFileHash hash ; + if(!getTunnelServiceInfo(item->tunnelId(),vpid,hash,service)) + return ; + service->receiveTurtleData(item,hash,vpid,item->travelingDirection()) ; +} + +//void p3turtle::handleRecvGenericDataItem(RsTurtleGenericDataItem *item) +//{ +//#ifdef P3TURTLE_DEBUG +// std::cerr << "p3Turtle: received Generic Data item:" << std::endl ; +// item->print(std::cerr,1) ; +//#endif +// std::string virtual_peer_id ; +// std::string hash ; +// RsTurtleClientService *service ; +// +// if(!getTunnelServiceInfo(item->tunnelId(),virtual_peer_id,hash,service)) +// return ; +// +// service->receiveTurtleData(item->data_bytes,item->data_size,hash,virtual_peer_id,item->travelingDirection()) ; +//} + +bool p3turtle::getTunnelServiceInfo(TurtleTunnelId tunnel_id,std::string& vpid,std::string& hash,RsTurtleClientService *& service) +{ + RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ + + std::map::iterator it2(_local_tunnels.find(tunnel_id)) ; + + if(it2 == _local_tunnels.end()) { - RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ - - std::map::iterator it2(_local_tunnels.find(item->tunnel_id)) ; - - if(it2 == _local_tunnels.end()) - { #ifdef P3TURTLE_DEBUG - std::cerr << "p3turtle: got file request with unknown tunnel id " << (void*)item->tunnel_id << std::endl ; + std::cerr << "p3turtle: unknown tunnel id " << (void*)item->tunnelId() << std::endl ; #endif - return ; - } - - TurtleTunnel& tunnel(it2->second) ; - std::map::const_iterator it(_outgoing_file_hashes.find(tunnel.hash)) ; -#ifdef P3TURTLE_DEBUG - assert(!tunnel.hash.empty()) ; - assert(it != _outgoing_file_hashes.end()) ; - - std::cerr << " This is an endpoint for this file request." << std::endl ; - std::cerr << " Forwarding data request to the multiplexer." << std::endl ; - std::cerr << " using peer_id=" << tunnel.vpid << ", hash=" << tunnel.hash << std::endl ; -#endif - size = it->second.size ; - vpid = tunnel.vpid ; - hash = tunnel.hash ; + return false; } - // This call is voluntarily off-mutex gards because it can cause cross mutex locks with the multiplexer. - // (Yeah, this bug was a shity hard one to catch). + TurtleTunnel& tunnel(it2->second) ; + +#ifdef P3TURTLE_DEBUG + assert(!tunnel.hash.empty()) ; + + std::cerr << " This is an endpoint for this file map." << std::endl ; + std::cerr << " Forwarding data to the multiplexer." << std::endl ; + std::cerr << " using peer_id=" << tunnel.vpid << ", hash=" << tunnel.hash << std::endl ; +#endif + // We should check that there is no backward call to the turtle router! // - _ft_server->getMultiplexer()->recvDataRequest(vpid,hash,size,item->chunk_offset,item->chunk_size) ; -} + vpid = tunnel.vpid ; + hash = tunnel.hash ; -void p3turtle::handleRecvFileData(RsTurtleFileDataItem *item) -{ -#ifdef P3TURTLE_DEBUG - std::cerr << "p3Turtle: received file data item:" << std::endl ; - item->print(std::cerr,1) ; -#endif - TurtleVirtualPeerId vpid ; - uint64_t size ; - TurtleFileHash hash ; + // Now sort out the case of client vs. server side items. + // + std::string ownid = mLinkMgr->getOwnId() ; + if(tunnel.local_src == ownid) { - RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ + std::map::const_iterator it = _incoming_file_hashes.find(hash) ; - _traffic_info_buffer.data_dn_Bps += static_cast(item)->serial_size() ; - - std::map::iterator it2(_local_tunnels.find(item->tunnel_id)) ; - - if(it2 == _local_tunnels.end()) + if(it == _incoming_file_hashes.end()) { -#ifdef P3TURTLE_DEBUG - std::cerr << "p3turtle: got file data with unknown tunnel id " << (void*)item->tunnel_id << std::endl ; -#endif - return ; + std::cerr << "p3turtle::handleRecvGenericTunnelItem(): hash " << hash << " for tunnel " << (void*)(it2->first) << " has no attached service! Dropping the item. This is a serious consistency error." << std::endl; + return false; } - TurtleTunnel& tunnel(it2->second) ; - std::map::iterator it( _incoming_file_hashes.find(tunnel.hash) ) ; -#ifdef P3TURTLE_DEBUG - assert(!tunnel.hash.empty()) ; -#endif - if(it==_incoming_file_hashes.end()) + service = it->second.service ; + } + else if(tunnel.local_dst == ownid) + { + std::map::const_iterator it = _outgoing_file_hashes.find(hash) ; + + if(it == _outgoing_file_hashes.end()) { -#ifdef P3TURTLE_DEBUG - std::cerr << "No tunnel for incoming data. Maybe the tunnel is being closed." << std::endl ; -#endif - return ; + std::cerr << "p3turtle::handleRecvGenericTunnelItem(): hash " << hash << " for tunnel " << (void*)(it2->first) << " has no attached service! Dropping the item. This is a serious consistency error." << std::endl; + return false; } - const TurtleFileHashInfo& hash_info(it->second) ; -#ifdef P3TURTLE_DEBUG - std::cerr << " This is an endpoint for this data chunk." << std::endl ; - std::cerr << " Forwarding data to the multiplexer." << std::endl ; - std::cerr << " using peer_id=" << tunnel.vpid << ", hash=" << tunnel.hash << std::endl ; -#endif - //_ft_server->getMultiplexer()->recvData(tunnel.vpid,tunnel.hash,hash_info.size,item->chunk_offset,item->chunk_size,item->chunk_data) ; - vpid = tunnel.vpid ; - hash = tunnel.hash ; - size = hash_info.size ; - - // also update the hash time stamp to show that it's actually being downloaded. - //it->second.time_stamp = time(NULL) ; + service = it->second; + } + else + { + std::cerr << "p3turtle::handleRecvGenericTunnelItem(): hash " << hash << " for tunnel " << (void*)(it2->first) << ". Tunnel is not a end-point or a starting tunnel!! This is a serious consistency error." << std::endl; + return false ; } - _ft_server->getMultiplexer()->recvData(vpid,hash,size,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 - // down _ft_server->getMultiplexer()->recvData()...in ftTransferModule::recvFileData -} - -void p3turtle::handleRecvFileMapRequest(RsTurtleFileMapRequestItem *item) -{ -#ifdef P3TURTLE_DEBUG - std::cerr << "p3Turtle: received file Map item:" << std::endl ; - item->print(std::cerr,1) ; -#endif - std::string hash,vpid ; - { - RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ - - std::map::iterator it2(_local_tunnels.find(item->tunnel_id)) ; - - if(it2 == _local_tunnels.end()) - { -#ifdef P3TURTLE_DEBUG - std::cerr << "p3turtle: got file data with unknown tunnel id " << (void*)item->tunnel_id << std::endl ; -#endif - return ; - } - - TurtleTunnel& tunnel(it2->second) ; -#ifdef P3TURTLE_DEBUG - assert(!tunnel.hash.empty()) ; - - std::cerr << " This is an endpoint for this file map request." << std::endl ; - std::cerr << " Forwarding data to the multiplexer." << std::endl ; - std::cerr << " using peer_id=" << tunnel.vpid << ", hash=" << tunnel.hash << std::endl ; -#endif - // we should check that there is no backward call to the turtle router! - // - hash = tunnel.hash ; - vpid = tunnel.vpid ; - } - - _ft_server->getMultiplexer()->recvChunkMapRequest(vpid,hash,item->direction == RsTurtleGenericTunnelItem::DIRECTION_CLIENT) ; -} - -void p3turtle::handleRecvFileMap(RsTurtleFileMapItem *item) -{ -#ifdef P3TURTLE_DEBUG - std::cerr << "p3Turtle: received file Map item:" << std::endl ; - item->print(std::cerr,1) ; -#endif - std::string hash,vpid ; - { - RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ - - std::map::iterator it2(_local_tunnels.find(item->tunnel_id)) ; - - if(it2 == _local_tunnels.end()) - { -#ifdef P3TURTLE_DEBUG - std::cerr << "p3turtle: got file data with unknown tunnel id " << (void*)item->tunnel_id << std::endl ; -#endif - return ; - } - - TurtleTunnel& tunnel(it2->second) ; - -#ifdef P3TURTLE_DEBUG - assert(!tunnel.hash.empty()) ; - - std::cerr << " This is an endpoint for this file map." << std::endl ; - std::cerr << " Forwarding data to the multiplexer." << std::endl ; - std::cerr << " using peer_id=" << tunnel.vpid << ", hash=" << tunnel.hash << std::endl ; -#endif - // We should check that there is no backward call to the turtle router! - // - vpid = tunnel.vpid ; - hash = tunnel.hash ; - } - _ft_server->getMultiplexer()->recvChunkMap(vpid,hash,item->compressed_map,item->direction == RsTurtleGenericTunnelItem::DIRECTION_CLIENT) ; -} - -void p3turtle::handleRecvFileCRC32MapRequest(RsTurtleFileCrcRequestItem *item) -{ -#ifdef P3TURTLE_DEBUG - std::cerr << "p3Turtle: received file CRC32 Map Request item:" << std::endl ; - item->print(std::cerr,1) ; -#endif - std::string hash,vpid ; - { - RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ - - std::map::iterator it2(_local_tunnels.find(item->tunnel_id)) ; - - if(it2 == _local_tunnels.end()) - { -#ifdef P3TURTLE_DEBUG - std::cerr << "p3turtle: got file data with unknown tunnel id " << (void*)item->tunnel_id << std::endl ; -#endif - return ; - } - - TurtleTunnel& tunnel(it2->second) ; -#ifdef P3TURTLE_DEBUG - assert(!tunnel.hash.empty()) ; - - std::cerr << " This is an endpoint for this file crc request." << std::endl ; - std::cerr << " Forwarding data to the multiplexer." << std::endl ; - std::cerr << " using peer_id=" << tunnel.vpid << ", hash=" << tunnel.hash << std::endl ; -#endif - // we should check that there is no backward call to the turtle router! - // - hash = tunnel.hash ; - vpid = tunnel.vpid ; - } - - _ft_server->getMultiplexer()->recvCRC32MapRequest(vpid,hash) ; -} -void p3turtle::handleRecvChunkCRC(RsTurtleChunkCrcItem *item) -{ -#ifdef P3TURTLE_DEBUG - std::cerr << "p3Turtle: received file CRC32 Map Request item:" << std::endl ; - item->print(std::cerr,1) ; -#endif - std::string hash,vpid ; - { - RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ - - std::map::iterator it2(_local_tunnels.find(item->tunnel_id)) ; - - if(it2 == _local_tunnels.end()) - { -#ifdef P3TURTLE_DEBUG - std::cerr << "p3turtle: chunk crc request with unknown tunnel id " << (void*)item->tunnel_id << std::endl ; -#endif - return ; - } - - TurtleTunnel& tunnel(it2->second) ; -#ifdef P3TURTLE_DEBUG - assert(!tunnel.hash.empty()) ; - - std::cerr << " This is an endpoint for this file crc request." << std::endl ; - std::cerr << " Forwarding data to the multiplexer." << std::endl ; - std::cerr << " using peer_id=" << tunnel.vpid << ", hash=" << tunnel.hash << std::endl ; -#endif - // we should check that there is no backward call to the turtle router! - // - hash = tunnel.hash ; - vpid = tunnel.vpid ; - } - - _ft_server->getMultiplexer()->recvSingleChunkCRC(vpid,hash,item->chunk_number,item->check_sum) ; -} -void p3turtle::handleRecvChunkCRCRequest(RsTurtleChunkCrcRequestItem *item) -{ -#ifdef P3TURTLE_DEBUG - std::cerr << "p3Turtle: received file CRC32 Map Request item:" << std::endl ; - item->print(std::cerr,1) ; -#endif - std::string hash,vpid ; - { - RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ - - std::map::iterator it2(_local_tunnels.find(item->tunnel_id)) ; - - if(it2 == _local_tunnels.end()) - { -#ifdef P3TURTLE_DEBUG - std::cerr << "p3turtle: chunk crc request with unknown tunnel id " << (void*)item->tunnel_id << std::endl ; -#endif - return ; - } - - TurtleTunnel& tunnel(it2->second) ; -#ifdef P3TURTLE_DEBUG - assert(!tunnel.hash.empty()) ; - - std::cerr << " This is an endpoint for this file crc request." << std::endl ; - std::cerr << " Forwarding data to the multiplexer." << std::endl ; - std::cerr << " using peer_id=" << tunnel.vpid << ", hash=" << tunnel.hash << std::endl ; -#endif - // we should check that there is no backward call to the turtle router! - // - hash = tunnel.hash ; - vpid = tunnel.vpid ; - } - - _ft_server->getMultiplexer()->recvSingleChunkCRCRequest(vpid,hash,item->chunk_number) ; -} -void p3turtle::handleRecvFileCRC32Map(RsTurtleFileCrcItem *item) -{ -#ifdef P3TURTLE_DEBUG - std::cerr << "p3Turtle: received file CRC32 Map item:" << std::endl ; - item->print(std::cerr,1) ; -#endif - std::string hash,vpid ; - { - RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ - - std::map::iterator it2(_local_tunnels.find(item->tunnel_id)) ; - - if(it2 == _local_tunnels.end()) - { -#ifdef P3TURTLE_DEBUG - std::cerr << "p3turtle: got file CRC32 map with unknown tunnel id " << (void*)item->tunnel_id << std::endl ; -#endif - return ; - } - - TurtleTunnel& tunnel(it2->second) ; - -#ifdef P3TURTLE_DEBUG - assert(!tunnel.hash.empty()) ; - - std::cerr << " This is an endpoint for this file map." << std::endl ; - std::cerr << " Forwarding data to the multiplexer." << std::endl ; - std::cerr << " using peer_id=" << tunnel.vpid << ", hash=" << tunnel.hash << std::endl ; -#endif - // We should check that there is no backward call to the turtle router! - // - vpid = tunnel.vpid ; - hash = tunnel.hash ; - } - _ft_server->getMultiplexer()->recvCRC32Map(vpid,hash,item->crc_map) ; + return true ; } // Send a data request into the correct tunnel for the given file hash -void p3turtle::sendDataRequest(const std::string& peerId, const std::string& , uint64_t, uint64_t offset, uint32_t chunksize) +// +void p3turtle::sendTurtleData(const std::string& virtual_peer_id,RsTurtleGenericTunnelItem *item) { RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ // get the proper tunnel for this file hash and peer id. - std::map::const_iterator it(_virtual_peers.find(peerId)) ; + std::map::const_iterator it(_virtual_peers.find(virtual_peer_id)) ; if(it == _virtual_peers.end()) { #ifdef P3TURTLE_DEBUG - std::cerr << "p3turtle::senddataRequest: cannot find virtual peer " << peerId << " in VP list." << std::endl ; + std::cerr << "p3turtle::senddataRequest: cannot find virtual peer " << virtual_peer_id << " in VP list." << std::endl ; #endif + delete item ; return ; } TurtleTunnelId tunnel_id = it->second ; - TurtleTunnel& tunnel(_local_tunnels[tunnel_id]) ; + std::map::iterator it2( _local_tunnels.find(tunnel_id) ) ; + + if(it2 == _local_tunnels.end()) + { + std::cerr << "p3turtle::client asked to send a packet through tunnel that has previously been deleted. Not a big issue unless it happens in masses." << std::endl; + delete item ; + return ; + } + TurtleTunnel& tunnel(it2->second) ; - RsTurtleFileRequestItem *item = new RsTurtleFileRequestItem ; item->tunnel_id = tunnel_id ; // we should randomly select a tunnel, or something more clever. - item->chunk_offset = offset ; - item->chunk_size = chunksize ; - item->PeerId(tunnel.local_dst) ; - -#ifdef P3TURTLE_DEBUG - std::cerr << "p3turtle: sending file req (chunksize=" << item->chunk_size << ", offset=" << item->chunk_offset << ", hash=0x" << tunnel.hash << ") through tunnel " << (void*)item->tunnel_id << ", next peer=" << tunnel.local_dst << std::endl ; -#endif - sendItem(item) ; -} - -// Send file data into the correct tunnel for the given file hash -void p3turtle::sendFileData(const std::string& peerId, const std::string& , uint64_t, uint64_t offset, uint32_t chunksize, void *data) -{ - RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ - - // get the proper tunnel for this file hash and peer id. - std::map::const_iterator it(_virtual_peers.find(peerId)) ; - - if(it == _virtual_peers.end()) - { -#ifdef P3TURTLE_DEBUG - std::cerr << "p3turtle::sendData: cannot find virtual peer " << peerId << " in VP list." << std::endl ; -#endif - return ; - } - TurtleTunnelId tunnel_id = it->second ; - TurtleTunnel& tunnel(_local_tunnels[tunnel_id]) ; - - tunnel.time_stamp = time(NULL) ; - - RsTurtleFileDataItem *item = new RsTurtleFileDataItem ; - item->tunnel_id = tunnel_id ; - item->chunk_offset = offset ; - item->chunk_size = chunksize ; - item->chunk_data = malloc(chunksize) ; - - tunnel.transfered_bytes += static_cast(item)->serial_size(); - - if(item->chunk_data == NULL) - { - std::cerr << "p3turtle: Warning: failed malloc of " << chunksize << " bytes for sending data packet." << std::endl ; - delete item; - return ; - } - memcpy(item->chunk_data,(void*)((uint8_t*)data),chunksize) ; - item->PeerId(tunnel.local_src) ; - -#ifdef P3TURTLE_DEBUG - std::cerr << "p3turtle: sending file data (chunksize=" << item->chunk_size << ", offset=" << item->chunk_offset << ", hash=0x" << tunnel.hash << ") through tunnel " << (void*)item->tunnel_id << ", next peer=" << tunnel.local_src << std::endl ; -#endif - _traffic_info_buffer.data_up_Bps += static_cast(item)->serial_size() ; - - sendItem(item) ; -} - -void p3turtle::sendChunkMapRequest(const std::string& peerId,const std::string& ,bool is_client) -{ - RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ - - // get the proper tunnel for this file hash and peer id. - std::map::const_iterator it(_virtual_peers.find(peerId)) ; - - if(it == _virtual_peers.end()) - { -#ifdef P3TURTLE_DEBUG - std::cerr << "p3turtle::senddataRequest: cannot find virtual peer " << peerId << " in VP list." << std::endl ; -#endif - return ; - } - TurtleTunnelId tunnel_id = it->second ; - TurtleTunnel& tunnel(_local_tunnels[tunnel_id]) ; - - RsTurtleFileMapRequestItem *item = new RsTurtleFileMapRequestItem ; - item->tunnel_id = tunnel_id ; std::string ownid = mLinkMgr->getOwnId() ; - if(tunnel.local_src == ownid) - { - assert(!is_client) ; - item->direction = RsTurtleGenericTunnelItem::DIRECTION_SERVER ; - item->PeerId(tunnel.local_dst) ; - } - else if(tunnel.local_dst == ownid) - { - assert(is_client) ; - item->direction = RsTurtleGenericTunnelItem::DIRECTION_CLIENT ; - item->PeerId(tunnel.local_src) ; - } - else - std::cerr << "p3turtle::sendChunkMapRequest: consistency error!" << std::endl ; - -#ifdef P3TURTLE_DEBUG - std::cerr << "p3turtle: sending chunk map req to peer " << peerId << ", hash=0x" << tunnel.hash << ") through tunnel " << (void*)item->tunnel_id << ", next peer=" << item->PeerId() << std::endl ; -#endif - sendItem(item) ; -} - -void p3turtle::sendChunkMap(const std::string& peerId,const std::string& ,const CompressedChunkMap& cmap,bool is_client) -{ - RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ - - // get the proper tunnel for this file hash and peer id. - std::map::const_iterator it(_virtual_peers.find(peerId)) ; - - if(it == _virtual_peers.end()) - { -#ifdef P3TURTLE_DEBUG - std::cerr << "p3turtle::senddataRequest: cannot find virtual peer " << peerId << " in VP list." << std::endl ; -#endif - return ; - } - TurtleTunnelId tunnel_id = it->second ; - TurtleTunnel& tunnel(_local_tunnels[tunnel_id]) ; - - RsTurtleFileMapItem *item = new RsTurtleFileMapItem ; - item->tunnel_id = tunnel_id ; - item->compressed_map = cmap ; - - std::string ownid = mLinkMgr->getOwnId() ; + if(item->shouldStampTunnel()) + tunnel.time_stamp = time(NULL) ; if(tunnel.local_src == ownid) { - assert(!is_client) ; - item->direction = RsTurtleGenericTunnelItem::DIRECTION_SERVER ; + item->setTravelingDirection(RsTurtleGenericTunnelItem::DIRECTION_SERVER) ; item->PeerId(tunnel.local_dst) ; + _traffic_info_buffer.data_dn_Bps += item->serial_size() ; } else if(tunnel.local_dst == ownid) { - assert(is_client) ; - item->direction = RsTurtleGenericTunnelItem::DIRECTION_CLIENT ; + item->setTravelingDirection(RsTurtleGenericTunnelItem::DIRECTION_CLIENT) ; item->PeerId(tunnel.local_src) ; + _traffic_info_buffer.data_up_Bps += item->serial_size() ; } else - std::cerr << "p3turtle::sendChunkMap: consistency error!" << std::endl ; - -#ifdef P3TURTLE_DEBUG - std::cerr << "p3turtle: sending chunk map to peer " << peerId << ", hash=0x" << tunnel.hash << ") through tunnel " << (void*)item->tunnel_id << ", next peer=" << item->PeerId() << std::endl ; -#endif - sendItem(item) ; -} -void p3turtle::sendSingleChunkCRC(const std::string& peerId,const std::string&,uint32_t chunk_number,const Sha1CheckSum& crc) -{ - RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ - - // get the proper tunnel for this file hash and peer id. - std::map::const_iterator it(_virtual_peers.find(peerId)) ; - - if(it == _virtual_peers.end()) { -#ifdef P3TURTLE_DEBUG - std::cerr << "p3turtle::sendCRC32MapRequest: cannot find virtual peer " << peerId << " in VP list." << std::endl ; -#endif + std::cerr << "p3Turtle::sendTurtleData(): asked to send a packet into a tunnel that is not registered. Dropping packet." << std::endl ; + delete item ; return ; } - TurtleTunnelId tunnel_id = it->second ; - TurtleTunnel& tunnel(_local_tunnels[tunnel_id]) ; - - RsTurtleChunkCrcItem *item = new RsTurtleChunkCrcItem; - item->tunnel_id = tunnel_id ; - item->chunk_number = chunk_number ; - item->check_sum = crc ; - item->PeerId(tunnel.local_dst) ; #ifdef P3TURTLE_DEBUG - std::cerr << "p3turtle: sending CRC32 map request to peer " << peerId << ", hash=0x" << tunnel.hash << ") through tunnel " << (void*)item->tunnel_id << ", next peer=" << item->PeerId() << std::endl ; -#endif - sendItem(item) ; -} -void p3turtle::sendSingleChunkCRCRequest(const std::string& peerId,const std::string&,uint32_t chunk_number) -{ - RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ - - // get the proper tunnel for this file hash and peer id. - std::map::const_iterator it(_virtual_peers.find(peerId)) ; - - if(it == _virtual_peers.end()) - { -#ifdef P3TURTLE_DEBUG - std::cerr << "p3turtle::sendCRC32MapRequest: cannot find virtual peer " << peerId << " in VP list." << std::endl ; -#endif - return ; - } - TurtleTunnelId tunnel_id = it->second ; - TurtleTunnel& tunnel(_local_tunnels[tunnel_id]) ; - - RsTurtleChunkCrcRequestItem *item = new RsTurtleChunkCrcRequestItem; - item->tunnel_id = tunnel_id ; - item->chunk_number = chunk_number ; - item->PeerId(tunnel.local_dst) ; - -#ifdef P3TURTLE_DEBUG - std::cerr << "p3turtle: sending CRC32 map request to peer " << peerId << ", hash=0x" << tunnel.hash << ") through tunnel " << (void*)item->tunnel_id << ", next peer=" << item->PeerId() << std::endl ; -#endif - sendItem(item) ; -} -void p3turtle::sendCRC32MapRequest(const std::string& peerId,const std::string& ) -{ - RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ - - // get the proper tunnel for this file hash and peer id. - std::map::const_iterator it(_virtual_peers.find(peerId)) ; - - if(it == _virtual_peers.end()) - { -#ifdef P3TURTLE_DEBUG - std::cerr << "p3turtle::sendCRC32MapRequest: cannot find virtual peer " << peerId << " in VP list." << std::endl ; -#endif - return ; - } - TurtleTunnelId tunnel_id = it->second ; - TurtleTunnel& tunnel(_local_tunnels[tunnel_id]) ; - - RsTurtleFileCrcRequestItem *item = new RsTurtleFileCrcRequestItem; - item->tunnel_id = tunnel_id ; -// item->crc_map = cmap ; - item->PeerId(tunnel.local_dst) ; - -#ifdef P3TURTLE_DEBUG - std::cerr << "p3turtle: sending CRC32 map request to peer " << peerId << ", hash=0x" << tunnel.hash << ") through tunnel " << (void*)item->tunnel_id << ", next peer=" << item->PeerId() << std::endl ; -#endif - sendItem(item) ; -} -void p3turtle::sendCRC32Map(const std::string& peerId,const std::string& ,const CRC32Map& cmap) -{ - RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ - - // get the proper tunnel for this file hash and peer id. - std::map::const_iterator it(_virtual_peers.find(peerId)) ; - - if(it == _virtual_peers.end()) - { -#ifdef P3TURTLE_DEBUG - std::cerr << "p3turtle::senddataRequest: cannot find virtual peer " << peerId << " in VP list." << std::endl ; -#endif - return ; - } - TurtleTunnelId tunnel_id = it->second ; - TurtleTunnel& tunnel(_local_tunnels[tunnel_id]) ; - - RsTurtleFileCrcItem *item = new RsTurtleFileCrcItem ; - item->tunnel_id = tunnel_id ; - item->crc_map = cmap ; - item->PeerId(tunnel.local_src) ; - -#ifdef P3TURTLE_DEBUG - std::cerr << "p3turtle: sending CRC32 map to peer " << peerId << ", hash=0x" << tunnel.hash << ") through tunnel " << (void*)item->tunnel_id << ", next peer=" << item->PeerId() << std::endl ; + std::cerr << "p3turtle: sending service packet to virtual peer id " << virtual_peer_id << ", hash=0x" << tunnel.hash << ", tunnel = " << (void*)item->tunnel_id << ", next peer=" << tunnel.local_dst << std::endl ; #endif sendItem(item) ; } @@ -1893,14 +1414,15 @@ void p3turtle::handleTunnelRequest(RsTurtleOpenTunnelItem *item) // We're off-mutex here. bool found = false ; - FileInfo info ; + std::string info ; + RsTurtleClientService *service = NULL ; if(item->PeerId() != mLinkMgr->getOwnId()) { #ifdef P3TURTLE_DEBUG std::cerr << " Request not from us. Performing local search" << std::endl ; #endif - found = (_sharing_strategy != SHARE_FRIENDS_ONLY || item->depth < 2) && performLocalHashSearch(item->file_hash,item->PeerId(),info) ; + found = performLocalHashSearch(item->file_hash,item->PeerId(),service) ; } { @@ -1936,11 +1458,17 @@ void p3turtle::handleTunnelRequest(RsTurtleOpenTunnelItem *item) // locked_addDistantPeer(item->file_hash,res_item->tunnel_id) ; - // Store the size of the file, to be able to re-form data requests to the multiplexer. + // Store some info string about the tunnel. // - _outgoing_file_hashes[item->file_hash] = info ; + _outgoing_file_hashes[item->file_hash] = service ; + + // Notify the client service that there's a new virtual peer id available as a client. + // + service->addVirtualPeer(item->file_hash,_local_tunnels[res_item->tunnel_id].vpid,RsTurtleGenericTunnelItem::DIRECTION_CLIENT) ; // We return straight, because when something is found, there's no need to digg a tunnel further. + // + return ; } #ifdef P3TURTLE_DEBUG @@ -2032,6 +1560,7 @@ void p3turtle::handleTunnelResult(RsTurtleTunnelOkItem *item) bool new_tunnel = false ; TurtleFileHash new_hash ; std::string new_vpid ; + RsTurtleClientService *service = NULL ; { RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ @@ -2101,7 +1630,7 @@ void p3turtle::handleTunnelResult(RsTurtleTunnelOkItem *item) // and this mostly prevents from sending the hash back in the tunnel. bool found = false ; - for(std::map::iterator it(_incoming_file_hashes.begin());it!=_incoming_file_hashes.end();++it) + for(std::map::iterator it(_incoming_file_hashes.begin());it!=_incoming_file_hashes.end();++it) if(it->second.last_request == item->request_id) { found = true ; @@ -2123,6 +1652,7 @@ void p3turtle::handleTunnelResult(RsTurtleTunnelOkItem *item) // new_tunnel = true ; new_hash = it->first ; + service = it->second.service ; locked_addDistantPeer(new_hash,item->tunnel_id) ; new_vpid = _local_tunnels[item->tunnel_id].vpid ; // save it for off-mutex usage. @@ -2146,11 +1676,8 @@ void p3turtle::handleTunnelResult(RsTurtleTunnelOkItem *item) // notify the file transfer controller for the new file source. This should be done off-mutex // so we deported this code here. // - if(new_tunnel && _ft_controller != NULL) - { - _ft_controller->addFileSource(new_hash,new_vpid) ; - _ft_controller->statusChange(_online_peers) ; - } + if(new_tunnel && service != NULL) + service->addVirtualPeer(new_hash,new_vpid,RsTurtleGenericTunnelItem::DIRECTION_SERVER) ; } // -----------------------------------------------------------------------------------// @@ -2305,7 +1832,7 @@ TurtleRequestId p3turtle::turtleSearch(const LinearizedExpression& expr) return id ; } -void p3turtle::monitorFileTunnels(const std::string& name,const std::string& file_hash,uint64_t size) +void p3turtle::monitorTunnels(const std::string& hash,RsTurtleClientService *client_service) { { RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ @@ -2313,36 +1840,35 @@ void p3turtle::monitorFileTunnels(const std::string& name,const std::string& fil // First, check if the hash is tagged for removal (there's a delay) for(uint32_t i=0;i<_hashes_to_remove.size();++i) - if(_hashes_to_remove[i] == file_hash) + if(_hashes_to_remove[i] == hash) { _hashes_to_remove[i] = _hashes_to_remove.back() ; _hashes_to_remove.pop_back() ; #ifdef P3TURTLE_DEBUG - std::cerr << "p3turtle: File hash " << file_hash << " Was scheduled for removal. Canceling the removal." << std::endl ; + std::cerr << "p3turtle: File hash " << hash << " Was scheduled for removal. Canceling the removal." << std::endl ; #endif } // Then, check if the hash is already there // - if(_incoming_file_hashes.find(file_hash) != _incoming_file_hashes.end()) // download already asked. + if(_incoming_file_hashes.find(hash) != _incoming_file_hashes.end()) // download already asked. { #ifdef P3TURTLE_DEBUG - std::cerr << "p3turtle: File hash " << file_hash << " already in pool. Returning." << std::endl ; + std::cerr << "p3turtle: File hash " << hash << " already in pool. Returning." << std::endl ; #endif return ; } #ifdef P3TURTLE_DEBUG - std::cerr << "p3turtle: Received order for turtle download fo hash " << file_hash << std::endl ; + std::cerr << "p3turtle: Received order for turtle download fo hash " << hash << std::endl ; #endif // No tunnels at start, but this triggers digging new tunnels. // - _incoming_file_hashes[file_hash].tunnels.clear(); + _incoming_file_hashes[hash].tunnels.clear(); // also should send associated request to the file transfer module. - _incoming_file_hashes[file_hash].size = size ; - _incoming_file_hashes[file_hash].name = name ; - _incoming_file_hashes[file_hash].last_digg_time = RSRandom::random_u32()%10 ; + _incoming_file_hashes[hash].last_digg_time = RSRandom::random_u32()%10 ; + _incoming_file_hashes[hash].service = client_service ; } IndicateConfigChanged() ; // initiates saving of handled hashes. @@ -2362,31 +1888,33 @@ void p3turtle::returnSearchResult(RsTurtleSearchResultItem *item) /// 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 std::string& peer_id,FileInfo& info) +bool p3turtle::performLocalHashSearch(const TurtleFileHash& hash,const std::string& peer_id,RsTurtleClientService *& service) { - bool res = rsFiles->FileDetails(hash, RS_FILE_HINTS_NETWORK_WIDE | RS_FILE_HINTS_LOCAL | RS_FILE_HINTS_EXTRA | RS_FILE_HINTS_SPEC_ONLY | RS_FILE_HINTS_DOWNLOAD, info); + if(_registered_services.empty()) + std::cerr << "Turtle router has no services registered. Tunnel requests cannot be handled." << std::endl; + for(std::list::const_iterator it(_registered_services.begin());it!=_registered_services.end();++it) + if( (*it)->handleTunnelRequest(hash,peer_id)) + { + service = *it ; + return true ; + } + + return false ; +} + + +void p3turtle::registerTunnelService(RsTurtleClientService *service) +{ #ifdef P3TURTLE_DEBUG - std::cerr << "p3turtle: performing local hash search for hash " << hash << std::endl; - - if(res) - { - std::cerr << "Found hash: " << std::endl; - std::cerr << " hash = " << hash << std::endl; - std::cerr << " peer = " << peer_id << std::endl; - std::cerr << " flags = " << info.storage_permission_flags << std::endl; - std::cerr << " local = " << rsFiles->FileDetails(hash, RS_FILE_HINTS_NETWORK_WIDE | RS_FILE_HINTS_LOCAL | RS_FILE_HINTS_EXTRA | RS_FILE_HINTS_SPEC_ONLY | RS_FILE_HINTS_DOWNLOAD, info) << std::endl; - std::cerr << " groups= " ; for(std::list::const_iterator it(info.parent_groups.begin());it!=info.parent_groups.end();++it) std::cerr << (*it) << ", " ; std::cerr << std::endl; - std::cerr << " clear = " << rsPeers->computePeerPermissionFlags(peer_id,info.storage_permission_flags,info.parent_groups) << std::endl; - } + for(std::list::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; - // The call to computeHashPeerClearance() return a combination of RS_FILE_HINTS_NETWORK_WIDE and RS_FILE_HINTS_BROWSABLE - // This is an additional computation cost, but the way it's written here, it's only called when res is true. - // - res = res && (RS_FILE_HINTS_NETWORK_WIDE & rsPeers->computePeerPermissionFlags(peer_id,info.storage_permission_flags,info.parent_groups)) ; - - return res ; + _registered_services.push_back(service) ; + _serialiser->registerClientService(service) ; } static std::string printFloatNumber(float num,bool friendly=false) @@ -2471,14 +1999,15 @@ void p3turtle::getInfo( std::vector >& hashes_info, hashes_info.clear() ; - for(std::map::const_iterator it(_incoming_file_hashes.begin());it!=_incoming_file_hashes.end();++it) + for(std::map::const_iterator it(_incoming_file_hashes.begin());it!=_incoming_file_hashes.end();++it) { hashes_info.push_back(std::vector()) ; std::vector& hashes(hashes_info.back()) ; hashes.push_back(it->first) ; - hashes.push_back(it->second.name) ; + //hashes.push_back(it->second.name) ; + hashes.push_back("Name not available") ; hashes.push_back(printNumber(it->second.tunnels.size())) ; //hashes.push_back(printNumber(now - it->second.time_stamp)+" secs ago") ; } @@ -2547,16 +2076,16 @@ void p3turtle::dumpState() std::cerr << std::endl ; std::cerr << "********************** Turtle router dump ******************" << std::endl ; std::cerr << " Active incoming file hashes: " << _incoming_file_hashes.size() << std::endl ; - for(std::map::const_iterator it(_incoming_file_hashes.begin());it!=_incoming_file_hashes.end();++it) + for(std::map::const_iterator it(_incoming_file_hashes.begin());it!=_incoming_file_hashes.end();++it) { - std::cerr << " hash=0x" << it->first << ", name=" << it->second.name << ", size=" << it->second.size << ", tunnel ids =" ; + std::cerr << " hash=0x" << it->first << ", tunnel ids =" ; for(std::vector::const_iterator it2(it->second.tunnels.begin());it2!=it->second.tunnels.end();++it2) std::cerr << " " << (void*)*it2 ; //std::cerr << ", last_req=" << (void*)it->second.last_request << ", time_stamp = " << it->second.time_stamp << "(" << now-it->second.time_stamp << " secs ago)" << std::endl ; } std::cerr << " Active outgoing file hashes: " << _outgoing_file_hashes.size() << std::endl ; - for(std::map::const_iterator it(_outgoing_file_hashes.begin());it!=_outgoing_file_hashes.end();++it) - std::cerr << " hash=0x" << it->first << ", name=" << it->second.fname << ", size=" << it->second.size << std::endl ; + for(std::map::const_iterator it(_outgoing_file_hashes.begin());it!=_outgoing_file_hashes.end();++it) + std::cerr << " hash=0x" << it->first << std::endl ; std::cerr << " Local tunnels:" << std::endl ; for(std::map::const_iterator it(_local_tunnels.begin());it!=_local_tunnels.end();++it) @@ -2583,8 +2112,8 @@ void p3turtle::dumpState() for(std::map::const_iterator it(_virtual_peers.begin());it!=_virtual_peers.end();++it) std::cerr << " id=" << it->first << ", tunnel=" << (void*)(it->second) << std::endl ; std::cerr << " Online peers: " << std::endl ; - for(std::list::const_iterator it(_online_peers.begin());it!=_online_peers.end();++it) - std::cerr << " id=" << it->id << ", name=" << it->name << ", state=" << it->state << ", actions=" << it->actions << std::endl ; +// for(std::list::const_iterator it(_online_peers.begin());it!=_online_peers.end();++it) +// std::cerr << " id=" << it->id << ", name=" << it->name << ", state=" << it->state << ", actions=" << it->actions << std::endl ; } #endif diff --git a/libretroshare/src/turtle/p3turtle.h b/libretroshare/src/turtle/p3turtle.h index 0d22a9107..aaa3f6d96 100644 --- a/libretroshare/src/turtle/p3turtle.h +++ b/libretroshare/src/turtle/p3turtle.h @@ -150,6 +150,7 @@ #include "ft/ftsearch.h" #include "retroshare/rsturtle.h" #include "rsturtleitem.h" +#include "turtleclientservice.h" #include "turtlestatistics.h" //#define TUNNEL_STATISTICS @@ -191,15 +192,14 @@ class TurtleTunnel // This class keeps trace of the activity for the file hashes the turtle router is asked to monitor. // -class TurtleFileHashInfo + +class TurtleHashInfo { public: std::vector tunnels ; // list of active tunnel ids for this file hash TurtleRequestId last_request ; // last request for the tunnels of this hash - - TurtleFileName name ; - time_t last_digg_time ; - uint64_t size ; + time_t last_digg_time ; // last time the tunnel digging happenned. + RsTurtleClientService *service ; // client service to which items should be sent. Never NULL. }; // Subclassing: @@ -216,22 +216,25 @@ class TurtleFileHashInfo class p3turtle: public p3Service, public RsTurtle, public p3Config { public: - p3turtle(p3LinkMgr *lm,ftServer *m); + p3turtle(p3LinkMgr *lm) ; // Enables/disable the service. Still ticks, but does nothing. Default is true. // virtual void setEnabled(bool) ; virtual bool enabled() const ; - // This is temporary, used by Operating Mode. + // This is temporary, used by Operating Mode. // Turtle operates when both enabled() && sessionEnabled() are true. - virtual void setSessionEnabled(bool); - virtual bool sessionEnabled() const; + virtual void setSessionEnabled(bool); + virtual bool sessionEnabled() const; // Lauches a search request through the pipes, and immediately returns // 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 LinearizedExpression& expr) ; @@ -247,12 +250,21 @@ class p3turtle: public p3Service, public RsTurtle, public p3Config // This function should be called in addition to ftServer::FileRequest() so that the turtle router // automatically provide tunnels for the file to download. // - virtual void monitorFileTunnels(const std::string& name,const std::string& file_hash,uint64_t size) ; + virtual void monitorTunnels(const std::string& file_hash,RsTurtleClientService *client_service) ; /// This should be called when canceling a file download, so that the turtle router stops /// handling tunnels for this file. /// - virtual void stopMonitoringFileTunnels(const std::string& file_hash) ; + virtual void stopMonitoringTunnels(const std::string& file_hash) ; + + /// Adds a client tunnel service. This means that the service will be added + /// to the list of services that might respond to tunnel requests. + /// Example tunnel services include: + /// + /// p3ChatService: tunnels correspond to private distant chatting + /// ftServer : tunnels correspond to file data transfer + /// + virtual void registerTunnelService(RsTurtleClientService *service) ; /// get info about tunnels virtual void getInfo(std::vector >&, @@ -277,7 +289,7 @@ class p3turtle: public p3Service, public RsTurtle, public p3Config virtual bool saveList(bool& cleanup, std::list&) ; virtual bool loadList(std::list& /*load*/) ; - /************* Communication with ftserver *******************/ + /************* Communication with clients *******************/ /// Does the turtle router manages tunnels to this peer ? (this is not a /// real id, but a fake one, that the turtle router is capable of connecting with a tunnel id). virtual bool isTurtlePeer(const std::string& peer_id) const ; @@ -296,28 +308,7 @@ class p3turtle: public p3Service, public RsTurtle, public p3Config void getVirtualPeersList(std::list& list) ; /// Send a data request into the correct tunnel for the given file hash - void sendDataRequest(const std::string& peerId, const std::string& hash, uint64_t size, uint64_t offset, uint32_t chunksize) ; - - /// Send file data into the correct tunnel for the given file hash - void sendFileData(const std::string& peerId, const std::string& hash, uint64_t size, uint64_t baseoffset, uint32_t chunksize, void *data) ; - - /// Send a request for the chunk map of this file to the given peer - void sendChunkMapRequest(const std::string& peerId, const std::string& hash,bool is_client) ; - - /// Send a chunk map of this file to the given peer - void sendChunkMap(const std::string& peerId, const std::string& hash,const CompressedChunkMap& cmap,bool is_client) ; - - /// Send a request for the crc32 map of this file to the given peer - void sendCRC32MapRequest(const std::string& peerId, const std::string& hash) ; - - /// Send a crc32 map of this file to the given peer - void sendCRC32Map(const std::string& peerId, const std::string& hash,const CRC32Map& cmap) ; - - /// Send a request for the CRC of a single chunk of this file to the given peer - void sendSingleChunkCRCRequest(const std::string& peerId, const std::string& hash,uint32_t chunk_number) ; - - /// Send a crc32 map of this file to the given peer - void sendSingleChunkCRC(const std::string& peerId, const std::string& hash,uint32_t chunk_number,const Sha1CheckSum& sum) ; + void sendTurtleData(const std::string& virtual_peer_id, RsTurtleGenericTunnelItem *item) ; private: //--------------------------- Admin/Helper functions -------------------------// @@ -360,18 +351,14 @@ class p3turtle: public p3Service, public RsTurtle, public p3Config void routeGenericTunnelItem(RsTurtleGenericTunnelItem *item) ; /// specific routing functions for handling particular packets. + void handleRecvGenericTunnelItem(RsTurtleGenericTunnelItem *item); + bool getTunnelServiceInfo(TurtleTunnelId, std::string& virtual_peer_id, std::string& hash, RsTurtleClientService*&) ; + + // following functions should go to ftServer void handleSearchRequest(RsTurtleSearchRequestItem *item); void handleSearchResult(RsTurtleSearchResultItem *item); void handleTunnelRequest(RsTurtleOpenTunnelItem *item); void handleTunnelResult(RsTurtleTunnelOkItem *item); - void handleRecvFileRequest(RsTurtleFileRequestItem *item); - void handleRecvFileData(RsTurtleFileDataItem *item); - void handleRecvFileMapRequest(RsTurtleFileMapRequestItem*); - void handleRecvFileMap(RsTurtleFileMapItem*); - void handleRecvFileCRC32MapRequest(RsTurtleFileCrcRequestItem*); - void handleRecvFileCRC32Map(RsTurtleFileCrcItem*); - void handleRecvChunkCRCRequest(RsTurtleChunkCrcRequestItem*); - void handleRecvChunkCRC(RsTurtleChunkCrcItem*); //------ Functions connecting the turtle router to other components.----------// @@ -382,14 +369,13 @@ class p3turtle: public p3Service, public RsTurtle, public p3Config void returnSearchResult(RsTurtleSearchResultItem *item) ; /// 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 std::string& client_peer_id,FileInfo& info) ; + virtual bool performLocalHashSearch(const TurtleFileHash& hash,const std::string& client_peer_id,RsTurtleClientService *& service); //--------------------------- Local variables --------------------------------// /* data */ p3LinkMgr *mLinkMgr; - ftServer *_ft_server ; - ftController *_ft_controller ; + RsTurtleSerialiser *_serialiser ; mutable RsMutex mTurtleMtx; @@ -400,10 +386,10 @@ class p3turtle: public p3Service, public RsTurtle, public p3Config std::map _tunnel_requests_origins ; /// stores adequate tunnels for each file hash locally managed - std::map _incoming_file_hashes ; + std::map _incoming_file_hashes ; /// stores file info for each file we provide. - std::map _outgoing_file_hashes ; + std::map _outgoing_file_hashes ; /// local tunnels, stored by ids (Either transiting or ending). std::map _local_tunnels ; @@ -414,6 +400,9 @@ class p3turtle: public p3Service, public RsTurtle, public p3Config /// Hashes marked to be deleted. std::vector _hashes_to_remove ; + /// List of client services that have regitered. + std::list _registered_services ; + time_t _last_clean_time ; time_t _last_tunnel_management_time ; time_t _last_tunnel_campaign_time ; diff --git a/libretroshare/src/turtle/rsturtleitem.cc b/libretroshare/src/turtle/rsturtleitem.cc index 739793e3e..9446e8686 100644 --- a/libretroshare/src/turtle/rsturtleitem.cc +++ b/libretroshare/src/turtle/rsturtleitem.cc @@ -4,6 +4,7 @@ #include #include "turtletypes.h" #include "rsturtleitem.h" +#include "turtleclientservice.h" //#define P3TURTLE_DEBUG // -----------------------------------------------------------------------------------// @@ -90,98 +91,14 @@ uint32_t RsTurtleTunnelOkItem::serial_size() return s ; } -uint32_t RsTurtleFileRequestItem::serial_size() +uint32_t RsTurtleGenericDataItem::serial_size() { uint32_t s = 0 ; s += 8 ; // header s += 4 ; // tunnel id - s += 8 ; // file offset - s += 4 ; // chunk size - - return s ; -} - -uint32_t RsTurtleFileDataItem::serial_size() -{ - uint32_t s = 0 ; - - s += 8 ; // header - s += 4 ; // tunnel id - s += 8 ; // file offset - s += 4 ; // chunk size - s += chunk_size ; // actual data size. - - return s ; -} - -uint32_t RsTurtleFileMapRequestItem::serial_size() -{ - uint32_t s = 0 ; - - s += 8 ; // header - s += 4 ; // tunnel id - s += 4 ; // direction - - return s ; -} - -uint32_t RsTurtleFileMapItem::serial_size() -{ - uint32_t s = 0 ; - - s += 8 ; // header - s += 4 ; // tunnel id - s += 4 ; // direction - s += 4 ; // compressed_map.size() - - s += 4 * compressed_map._map.size() ; - - return s ; -} - -uint32_t RsTurtleFileCrcRequestItem::serial_size() -{ - uint32_t s = 0 ; - - s += 8 ; // header - s += 4 ; // tunnel id - - return s ; -} -uint32_t RsTurtleChunkCrcItem::serial_size() -{ - uint32_t s = 0 ; - - s += 8 ; // header - s += 4 ; // tunnel id - s += 4 ; // chunk number - s += 20 ; // check_sum - - return s ; -} -uint32_t RsTurtleChunkCrcRequestItem::serial_size() -{ - uint32_t s = 0 ; - - s += 8 ; // header - s += 4 ; // tunnel id - s += 4 ; // chunk number - - return s ; -} -uint32_t RsTurtleFileCrcItem::serial_size() -{ - uint32_t s = 0 ; - - s += 8 ; // header - s += 4 ; // tunnel id - - s += 4 ; // size of _map - s += 4 ; // size of _crcs - - s += 4 * crc_map._crcs.size() ; - s += 4 * crc_map._ccmap._map.size() ; + s += 4 ; // data size + s += data_size ; // data return s ; } @@ -216,19 +133,21 @@ RsItem *RsTurtleSerialiser::deserialise(void *data, uint32_t *size) case RS_TURTLE_SUBTYPE_SEARCH_RESULT : return new RsTurtleSearchResultItem(data,*size) ; case RS_TURTLE_SUBTYPE_OPEN_TUNNEL : return new RsTurtleOpenTunnelItem(data,*size) ; case RS_TURTLE_SUBTYPE_TUNNEL_OK : return new RsTurtleTunnelOkItem(data,*size) ; - case RS_TURTLE_SUBTYPE_FILE_REQUEST : return new RsTurtleFileRequestItem(data,*size) ; - case RS_TURTLE_SUBTYPE_FILE_DATA : return new RsTurtleFileDataItem(data,*size) ; - case RS_TURTLE_SUBTYPE_FILE_MAP_REQUEST : return new RsTurtleFileMapRequestItem(data,*size) ; - case RS_TURTLE_SUBTYPE_FILE_MAP : return new RsTurtleFileMapItem(data,*size) ; - case RS_TURTLE_SUBTYPE_FILE_CRC_REQUEST : return new RsTurtleFileCrcRequestItem(data,*size) ; - case RS_TURTLE_SUBTYPE_FILE_CRC : return new RsTurtleFileCrcItem(data,*size) ; - case RS_TURTLE_SUBTYPE_CHUNK_CRC_REQUEST : return new RsTurtleChunkCrcRequestItem(data,*size) ; - case RS_TURTLE_SUBTYPE_CHUNK_CRC : return new RsTurtleChunkCrcItem(data,*size) ; - + case RS_TURTLE_SUBTYPE_GENERIC_DATA : return new RsTurtleGenericDataItem(data,*size) ; + default: - std::cerr << "Unknown packet type in RsTurtle!" << std::endl ; - return NULL ; + break ; } + // now try all client services + // + RsItem *item = NULL ; + + for(uint32_t i=0;i<_client_services.size();++i) + if((item = _client_services[i]->deserialiseItem(data,*size)) != NULL) + return item ; + + std::cerr << "Unknown packet type in RsTurtle (not even handled by client services)!" << std::endl ; + return NULL ; #ifndef WINDOWS_SYS } catch(std::exception& e) @@ -240,224 +159,6 @@ RsItem *RsTurtleSerialiser::deserialise(void *data, uint32_t *size) } -bool RsTurtleFileMapRequestItem::serialize(void *data,uint32_t& pktsize) -{ - uint32_t tlvsize = serial_size(); - uint32_t offset = 0; - - if (pktsize < tlvsize) - return false; /* not enough space */ - - pktsize = tlvsize; - - bool ok = true; - - ok &= setRsItemHeader(data,tlvsize,PacketId(), tlvsize); - - /* skip the header */ - offset += 8; - - /* add mandatory parts first */ - - ok &= setRawUInt32(data, tlvsize, &offset, tunnel_id); - ok &= setRawUInt32(data, tlvsize, &offset, direction); - - if (offset != tlvsize) - { - ok = false; -#ifdef RSSERIAL_DEBUG - std::cerr << "RsFileConfigSerialiser::serialiseTransfer() Size Error! " << std::endl; -#endif - } - - return ok; -} - -bool RsTurtleFileMapItem::serialize(void *data,uint32_t& pktsize) -{ - uint32_t tlvsize = serial_size(); - uint32_t offset = 0; - - if (pktsize < tlvsize) - return false; /* not enough space */ - - pktsize = tlvsize; - - bool ok = true; - - ok &= setRsItemHeader(data,tlvsize,PacketId(), tlvsize); - - /* skip the header */ - offset += 8; - - /* add mandatory parts first */ - - ok &= setRawUInt32(data, tlvsize, &offset, tunnel_id); - ok &= setRawUInt32(data, tlvsize, &offset, direction); - ok &= setRawUInt32(data, tlvsize, &offset, compressed_map._map.size()); - - for(uint32_t i=0;i(item)->serialize(data,*size) ; } virtual RsItem *deserialise (void *data, uint32_t *size) ; + + // This is used by the turtle router to add services to its serialiser. + // Client services are only used for deserialising, since the serialisation is + // performed using the overloaded virtual functions above. + // + void registerClientService(RsTurtleClientService *service) { _client_services.push_back(service) ; } + + private: + std::vector _client_services ; }; diff --git a/libretroshare/src/turtle/turtleclientservice.h b/libretroshare/src/turtle/turtleclientservice.h new file mode 100644 index 000000000..d802a6b78 --- /dev/null +++ b/libretroshare/src/turtle/turtleclientservice.h @@ -0,0 +1,86 @@ +/* + * libretroshare/src/services: turtleclientservice.h + * + * Services for RetroShare. + * + * Copyright 2013 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 "csoler@users.sourceforge.net". + * + */ + +// This class is the parent class for any service that will use the turtle router to distribute its packets. +// Typical representative clients include: +// +// p3ChatService: opens tunnels to distant peers for chatting +// ftServer: searches and open tunnels to distant sources for file transfer +// +#pragma once + +#include +#include +#include +#include + +class RsItem ; + +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. + + virtual bool handleTunnelRequest(const std::string& hash,const std::string& 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 std::string& hash,const std::string& 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 deserialising 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 + + virtual RsTurtleGenericTunnelItem *deserialiseItem(void *data, uint32_t size) const { return NULL ; } + + // These methods are called by the turtle router to add/remove virtual peers when tunnels are created/deleted + // + 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 ; +}; + + diff --git a/libretroshare/src/util/rsaes.cc b/libretroshare/src/util/rsaes.cc new file mode 100644 index 000000000..a7eeec85c --- /dev/null +++ b/libretroshare/src/util/rsaes.cc @@ -0,0 +1,138 @@ +/* + * libretroshare/src/utils: rsaes.cc + * + * AES crptography for RetroShare. + * + * Copyright 2013 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 "csoler@users.sourceforge.net". + * + */ + +#include +#include +#include + +#include "rsaes.h" + +uint32_t RsAES::get_buffer_size(uint32_t n) +{ + return n + AES_BLOCK_SIZE ; +} + +bool RsAES::aes_crypt_8_16(const uint8_t *input_data,uint32_t input_data_length,uint8_t key_data[16],uint8_t salt[8],uint8_t *output_data,uint32_t& output_data_length) +{ + int nrounds = 5; + uint8_t key[32], iv[32]; + + /* + * Gen key & IV for AES 256 CBC mode. A SHA1 digest is used to hash the supplied key material. + * nrounds is the number of times the we hash the material. More rounds are more secure but + * slower. + */ + int i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), salt, key_data, 16, nrounds, key, iv); + + if (i != 32) + { + printf("Key size is %d bits - should be 256 bits\n", i); + return false ; + } + + EVP_CIPHER_CTX e_ctx ; + EVP_CIPHER_CTX_init(&e_ctx); + EVP_EncryptInit_ex(&e_ctx, EVP_aes_256_cbc(), NULL, key, iv); + + /* max ciphertext len for a n bytes of plaintext is n + AES_BLOCK_SIZE -1 bytes */ + int c_len = input_data_length + AES_BLOCK_SIZE ; + int f_len = 0; + + if(output_data_length < (uint32_t)c_len) + return false ; + + /* update ciphertext, c_len is filled with the length of ciphertext generated, + *len is the size of plaintext in bytes */ + + if(!EVP_EncryptUpdate(&e_ctx, output_data, &c_len, input_data, input_data_length)) + { + std::cerr << "RsAES: decryption failed at end. Check padding." << std::endl; + return false ; + } + + /* update ciphertext with the final remaining bytes */ + if(!EVP_EncryptFinal_ex(&e_ctx, output_data+c_len, &f_len)) + { + std::cerr << "RsAES: decryption failed at end. Check padding." << std::endl; + return false ; + } + + output_data_length = c_len + f_len; + + return true; +} + +bool RsAES::aes_decrypt_8_16(const uint8_t *input_data,uint32_t input_data_length,uint8_t key_data[16],uint8_t salt[8],uint8_t *output_data,uint32_t& output_data_length) +{ + int nrounds = 5; + uint8_t key[32], iv[32]; + + /* + * Gen key & IV for AES 256 CBC mode. A SHA1 digest is used to hash the supplied key material. + * nrounds is the number of times the we hash the material. More rounds are more secure but + * slower. + */ + int i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), salt, key_data, 16, nrounds, key, iv); + + if (i != 32) + { + printf("Key size is %d bits - should be 256 bits\n", i); + return false ; + } + + EVP_CIPHER_CTX e_ctx ; + EVP_CIPHER_CTX_init(&e_ctx); + EVP_DecryptInit_ex(&e_ctx, EVP_aes_256_cbc(), NULL, key, iv); + + /* max ciphertext len for a n bytes of plaintext is n + AES_BLOCK_SIZE -1 bytes */ + int c_len = input_data_length + AES_BLOCK_SIZE ; + int f_len = 0; + + if(output_data_length < (uint32_t)c_len) + return false ; + + output_data_length = c_len ; + + /* update ciphertext, c_len is filled with the length of ciphertext generated, + *len is the size of plaintext in bytes */ + + if(! EVP_DecryptUpdate(&e_ctx, output_data, &c_len, input_data, input_data_length)) + { + std::cerr << "RsAES: decryption failed." << std::endl; + return false ; + } + + /* update ciphertext with the final remaining bytes */ + if(!EVP_DecryptFinal_ex(&e_ctx, output_data+c_len, &f_len)) + { + std::cerr << "RsAES: decryption failed at end. Check padding." << std::endl; + return false ; + } + + output_data_length = c_len + f_len; + + return true; +} + diff --git a/libretroshare/src/util/rsaes.h b/libretroshare/src/util/rsaes.h new file mode 100644 index 000000000..21a8c701c --- /dev/null +++ b/libretroshare/src/util/rsaes.h @@ -0,0 +1,47 @@ +/* + * libretroshare/src/utils: rsaescrypt.h + * + * AES crptography for RetroShare. + * + * Copyright 2013 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 "csoler@users.sourceforge.net". + * + */ + +#include + +class RsAES +{ + public: + // Crypt/decrypt data using a 16 bytes key and a 8 bytes salt. + // + // output_data allocation is left to the client. The size should be at least RsAES::get_buffer_size(input_data_length) + // + // Return value: + // true: encryption/decryption ok + // + // false: encryption/decryption went bad. Check buffer size. + // + static bool aes_crypt_8_16(const uint8_t *input_data,uint32_t input_data_length,uint8_t key[16],uint8_t salt[8],uint8_t *output_data,uint32_t& output_data_length) ; + static bool aes_decrypt_8_16(const uint8_t *input_data,uint32_t input_data_length,uint8_t key[16],uint8_t salt[8],uint8_t *output_data,uint32_t& output_data_length) ; + + // computes the safe buffer size to store encrypted/decrypted data for the given input stream size + // + static uint32_t get_buffer_size(uint32_t size) ; +}; + diff --git a/libretroshare/src/util/rsrandom.cc b/libretroshare/src/util/rsrandom.cc index 071511b75..fc668ded2 100644 --- a/libretroshare/src/util/rsrandom.cc +++ b/libretroshare/src/util/rsrandom.cc @@ -51,6 +51,10 @@ bool RSRandom::seed(uint32_t s) return true ; } +void RSRandom::random_bytes(unsigned char *data,uint32_t size) +{ + RAND_bytes(data,size) ; +} void RSRandom::locked_next_state() { #ifdef RSRANDOM_USE_SSL diff --git a/libretroshare/src/util/rsrandom.h b/libretroshare/src/util/rsrandom.h index aabec8905..f69211405 100644 --- a/libretroshare/src/util/rsrandom.h +++ b/libretroshare/src/util/rsrandom.h @@ -46,6 +46,7 @@ class RSRandom static bool seed(uint32_t s) ; static std::string random_alphaNumericString(uint32_t length) ; + static void random_bytes(unsigned char *data,uint32_t length) ; private: static RsMutex rndMtx ; diff --git a/plugins/VOIP/gui/AudioPopupChatDialog.cpp b/plugins/VOIP/gui/AudioPopupChatDialog.cpp index 71135ccf6..75afbf264 100644 --- a/plugins/VOIP/gui/AudioPopupChatDialog.cpp +++ b/plugins/VOIP/gui/AudioPopupChatDialog.cpp @@ -49,8 +49,8 @@ AudioPopupChatDialog::AudioPopupChatDialog(QWidget *parent) connect(audioListenToggleButton, SIGNAL(clicked()), this , SLOT(toggleAudioListen())); connect(audioMuteCaptureToggleButton, SIGNAL(clicked()), this , SLOT(toggleAudioMuteCapture())); - addButton(audioListenToggleButton) ; - addButton(audioMuteCaptureToggleButton) ; + addChatBarWidget(audioListenToggleButton) ; + addChatBarWidget(audioMuteCaptureToggleButton) ; //ui.chatWidget->resetStatusBar(); diff --git a/retroshare-gui/src/gui/CreateMsgLinkDialog.cpp b/retroshare-gui/src/gui/CreateMsgLinkDialog.cpp new file mode 100644 index 000000000..8972f90c3 --- /dev/null +++ b/retroshare-gui/src/gui/CreateMsgLinkDialog.cpp @@ -0,0 +1,226 @@ +/**************************************************************** + * RetroShare is distributed under the following license: + * + * Copyright (C) 2013 Cyril Soler + * + * This program is free software; you can redistribute it and/or + * as published by the Free Software Foundation; either version 2 + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + ****************************************************************/ + +#include +#include +#include +#include +#include +#include "CreateMsgLinkDialog.h" +#include +#include + +CreateMsgLinkDialog::CreateMsgLinkDialog(QWidget *parent) + :QDialog(NULL, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint) +{ + /* Invoke the Qt Designer generated object setup routine */ + setupUi(this); + + setAttribute(Qt::WA_DeleteOnClose, false); + + _info_GB->layout()->addWidget( _gpg_selection = new FriendSelectionWidget(this) ) ; + + QObject::connect(_link_type_CB,SIGNAL(currentIndexChanged(int)),this,SLOT(update())) ; + QObject::connect(_create_link_PB,SIGNAL(clicked()),this,SLOT(createLink())) ; + QObject::connect(_create_new_PB,SIGNAL(toggled(bool)),this,SLOT(toggleCreateLink(bool))) ; + QObject::connect(_existing_links_LW,SIGNAL(currentRowChanged(int)),this,SLOT(updateCurrentRow(int))) ; + + _gpg_selection->setModus(FriendSelectionWidget::MODUS_SINGLE) ; + _gpg_selection->setShowType(FriendSelectionWidget::SHOW_NON_FRIEND_GPG | FriendSelectionWidget::SHOW_GPG) ; + _gpg_selection->setHeaderText(QObject::tr("Select who can contact you:")) ; + _gpg_selection->start() ; + + toggleCreateLink(false) ; + update() ; + updateCurrentRow(-1) ; +} + +void CreateMsgLinkDialog::updateCurrentRow(int r) +{ + if(r < 0) + { + _current_link_type_LE->setText("") ; + _current_link_dst_LE->setText("") ; + _current_link_date_DE->setDateTime(QDateTime::fromMSecsSinceEpoch(0)) ; + return ; + } + + QUrl text = _existing_links_LW->item(r)->data(Qt::UserRole).toUrl() ; + + std::cerr << "Parsing link : " << text.toString().toStdString() << std::endl; + RetroShareLink link(text) ; + + if( link.type() == RetroShareLink::TYPE_PRIVATE_CHAT ) + _current_link_type_LE->setText( tr("Private chat invite") ) ; + else + _current_link_type_LE->setText( tr("Public message invite") ) ; + + _current_link_dst_LE->setText(link.GPGId()) ; + _current_link_date_DE->setDateTime(QDateTime::fromMSecsSinceEpoch(link.timeStamp() * 1000 )) ; +} + +void CreateMsgLinkDialog::toggleCreateLink(bool b) +{ + _new_link_F->setHidden(!b) ; +} +void CreateMsgLinkDialog::update() +{ + if(_link_type_CB->currentIndex() == 0) + { + QString s ; + + s += "A private chat invite allows a specific peer to contact you using encrypted private chat. You need to select a destination peer from your PGP keyring before creating the link. The link contains the encryption code and your PGP signature, so that the peer can authenticate you." ; + + _info_TB->setHtml(s) ; + _gpg_selection->setHidden(false) ; + } + else + { + QString s ; + + s += "A public message link allows any peer in the nearby network to send a private message to you. The message is encrypted and only you can read it." ; + + _info_TB->setHtml(s) ; + _gpg_selection->setHidden(true) ; + } + + std::vector invites ; + + rsMsgs->getDistantChatInviteList(invites) ; + + _existing_links_LW->clear() ; + + for(uint32_t i=0;isetData(Qt::DisplayRole,tr("Private chat invite to ")+QString::fromStdString(invites[i].destination_pgp_id)) ; + item->setData(Qt::UserRole,link.toString()) ; + + _existing_links_LW->insertItem(0,item) ; + } + + std::vector invites2 ; + rsMsgs->getDistantOfflineMessengingInvites(invites2) ; + + for(uint32_t i=0;isetData(Qt::DisplayRole,tr("Public message link")) ; + item->setData(Qt::UserRole,link.toString()) ; + + _existing_links_LW->insertItem(0,item) ; + } + } + + +} + +time_t CreateMsgLinkDialog::computeValidityDuration() const +{ + time_t unit ; + + switch(_validity_time_CB->currentIndex()) + { + default: + case 0: unit = 3600 ; + break ; + case 1: unit = 3600*24 ; + break ; + case 2: unit = 3600*24*7 ; + break ; + case 3: unit = 3600*24*30 ; + break ; + case 4: unit = 3600*24*365 ; + break ; + } + + return unit * _validity_time_SB->value() ; +} + +void CreateMsgLinkDialog::createLink() +{ + std::cerr << "Creating link!" << std::endl; + + if(_link_type_CB->currentIndex() == 0) + { + time_t validity_duration = computeValidityDuration() ; + FriendSelectionWidget::IdType type ; + std::string current_pgp_id = _gpg_selection->selectedId(type) ; + + std::string encrypted_string ; + + bool res = rsMsgs->createDistantChatInvite(current_pgp_id,validity_duration,encrypted_string) ; + + RetroShareLink link ; + + if(!link.createPrivateChatInvite(validity_duration + time(NULL),QString::fromStdString(current_pgp_id),QString::fromStdString(encrypted_string)) ) + std::cerr << "Cannot create link." << std::endl; + + QList links ; + links.push_back(link) ; + + RSLinkClipboard::copyLinks(links) ; + + if(!res) + QMessageBox::critical(NULL,tr("Private chat invite creation failed"),tr("The creation of the chat invite failed")) ; + else + QMessageBox::information(NULL,tr("Private chat invite created"),tr("Your new chat invite has been copied to clipboard. You can now paste it as a Retroshare link.")) ; + } + else + { + time_t validity_duration = computeValidityDuration() ; + std::string hash; + std::string issuer_pgp_id = rsPeers->getGPGOwnId() ; + + bool res = rsMsgs->createDistantOfflineMessengingInvite(validity_duration,hash) ; + + RetroShareLink link ; + + if(!link.createPublicMsgInvite(validity_duration + time(NULL),QString::fromStdString(issuer_pgp_id),QString::fromStdString(hash)) ) + { + std::cerr << "Cannot create link." << std::endl; + return ; + } + + QList links ; + links.push_back(link) ; + + RSLinkClipboard::copyLinks(links) ; + + if(!res) + QMessageBox::critical(NULL,tr("Messenging invite creation failed"),tr("The creation of the messenging invite failed")) ; + else + QMessageBox::information(NULL,tr("Messenging invite created"),tr("Your new messenging chat invite has been copied to clipboard. You can now paste it as a Retroshare link.")) ; + } + + QTimer::singleShot(100,this,SLOT(update())) ; +} + diff --git a/retroshare-gui/src/gui/CreateMsgLinkDialog.h b/retroshare-gui/src/gui/CreateMsgLinkDialog.h new file mode 100644 index 000000000..bd8dc7db0 --- /dev/null +++ b/retroshare-gui/src/gui/CreateMsgLinkDialog.h @@ -0,0 +1,53 @@ +/**************************************************************** + * RetroShare is distributed under the following license: + * + * Copyright (C) 2008 Robert Fernie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + ******************************************************************/ + +#pragma once + +#include "ui_CreateMsgLinkDialog.h" + +class FriendSelectionWidget ; + +class CreateMsgLinkDialog : public QDialog, public Ui::CreateMsgLinkDialog +{ + Q_OBJECT + + public: + CreateMsgLinkDialog(QWidget *parent = NULL); + virtual ~CreateMsgLinkDialog() {} + + private slots: + /* actions to take.... */ + void createLink(); + void update() ; + void toggleCreateLink(bool) ; + void updateCurrentRow(int) ; + + private: + time_t computeValidityDuration() const ; + + /** Qt Designer generated object */ + FriendSelectionWidget *_gpg_selection ; +}; + + + + + diff --git a/retroshare-gui/src/gui/CreateMsgLinkDialog.ui b/retroshare-gui/src/gui/CreateMsgLinkDialog.ui new file mode 100644 index 000000000..d5a23d8c4 --- /dev/null +++ b/retroshare-gui/src/gui/CreateMsgLinkDialog.ui @@ -0,0 +1,220 @@ + + + CreateMsgLinkDialog + + + + 0 + 0 + 565 + 465 + + + + Dialog + + + + + + + + + 0 + 0 + + + + + + + + + + + + + + Valid until: + + + + + + + Type: + + + + + + + Usable by: + + + + + + + + + + + + + + + + + + + + + + + + + + Copy to clipboard + + + + + + + Create new + + + true + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + Invite type: + + + + + + + + Private chat + + + + + Public message + + + + + + + + Validity time : + + + + + + + 1 + + + 30 + + + 5 + + + + + + + + hour + + + + + day + + + + + week + + + + + month + + + + + year + + + + + + + + Create! + + + + + + + + + Information + + + + + + + + + + + + + + + + diff --git a/retroshare-gui/src/gui/MessagesDialog.cpp b/retroshare-gui/src/gui/MessagesDialog.cpp index ef18b9dc7..571a0744e 100644 --- a/retroshare-gui/src/gui/MessagesDialog.cpp +++ b/retroshare-gui/src/gui/MessagesDialog.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "MessagesDialog.h" @@ -118,8 +119,8 @@ MessagesDialog::MessagesDialog(QWidget *parent) inChange = false; lockUpdate = 0; - connect(ui.messagestreeView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(messageslistWidgetCostumPopupMenu(QPoint))); - connect(ui.listWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(folderlistWidgetCostumPopupMenu(QPoint))); + connect(ui.messagestreeView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(messageslistWidgetCustomPopupMenu(QPoint))); + connect(ui.listWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(folderlistWidgetCustomPopupMenu(QPoint))); connect(ui.messagestreeView, SIGNAL(clicked(const QModelIndex&)) , this, SLOT(clicked(const QModelIndex&))); connect(ui.messagestreeView, SIGNAL(doubleClicked(const QModelIndex&)) , this, SLOT(doubleClicked(const QModelIndex&))); connect(ui.listWidget, SIGNAL(currentRowChanged(int)), this, SLOT(changeBox(int))); @@ -507,7 +508,7 @@ bool MessagesDialog::hasMessageStar(int nRow) return item->data(ROLE_MSGFLAGS).toInt() & RS_MSG_STAR; } -void MessagesDialog::messageslistWidgetCostumPopupMenu( QPoint /*point*/ ) +void MessagesDialog::messageslistWidgetCustomPopupMenu( QPoint /*point*/ ) { std::string cid; std::string mid; @@ -587,6 +588,9 @@ void MessagesDialog::messageslistWidgetCostumPopupMenu( QPoint /*point*/ ) action->setDisabled(true); } + if(nCount==1 && (msgInfo.msgflags & RS_MSG_ENCRYPTED)) + action = contextMnu.addAction(QIcon(IMAGE_SYSTEM), tr("Decrypt Message"), this, SLOT(decryptSelectedMsg())); + int listrow = ui.listWidget->currentRow(); if (listrow == ROW_TRASHBOX) { action = contextMnu.addAction(tr("Undelete"), this, SLOT(undeletemessage())); @@ -605,7 +609,7 @@ void MessagesDialog::messageslistWidgetCostumPopupMenu( QPoint /*point*/ ) contextMnu.exec(QCursor::pos()); } -void MessagesDialog::folderlistWidgetCostumPopupMenu(QPoint /*point*/) +void MessagesDialog::folderlistWidgetCustomPopupMenu(QPoint /*point*/) { if (ui.listWidget->currentRow() != ROW_TRASHBOX) { /* Context menu only neede for trash box */ @@ -1112,7 +1116,11 @@ void MessagesDialog::insertMessages() } // Subject - text = QString::fromStdWString(it->title); + if(it->msgflags & RS_MSG_ENCRYPTED) + text = tr("Encrypted message. Right-click to decrypt it.") ; + else + text = QString::fromStdWString(it->title); + item[COLUMN_SUBJECT]->setText(text); item[COLUMN_SUBJECT]->setData(text + dateString, ROLE_SORT); @@ -1464,6 +1472,28 @@ void MessagesDialog::insertMsgTxtAndFiles(QModelIndex Index, bool bSetToRead) updateInterface(); } +void MessagesDialog::decryptSelectedMsg() +{ + MessageInfo msgInfo; + + if (!rsMsgs->getMessage(mCurrMsgId, msgInfo)) + return ; + + if(!msgInfo.msgflags & RS_MSG_ENCRYPTED) + { + std::cerr << "This message is not encrypted! Cannot decrypt!" << std::endl; + return ; + } + + if(!rsMsgs->decryptMessage(mCurrMsgId) ) + QMessageBox::warning(NULL,tr("Decryption failed!"),tr("This message could not be decrypted.")) ; + + //setMsgAsReadUnread(currentIndex.row(), true); + updateMessageSummaryList(); + insertMessages(); + insertMsgTxtAndFiles(); +} + bool MessagesDialog::getCurrentMsg(std::string &cid, std::string &mid) { QModelIndex currentIndex = ui.messagestreeView->currentIndex(); diff --git a/retroshare-gui/src/gui/MessagesDialog.h b/retroshare-gui/src/gui/MessagesDialog.h index 978b6f7f8..6308cf786 100644 --- a/retroshare-gui/src/gui/MessagesDialog.h +++ b/retroshare-gui/src/gui/MessagesDialog.h @@ -60,8 +60,9 @@ public slots: private slots: /** Create the context popup menu and it's submenus */ - void messageslistWidgetCostumPopupMenu( QPoint point ); - void folderlistWidgetCostumPopupMenu(QPoint); + void messageslistWidgetCustomPopupMenu( QPoint point ); + void folderlistWidgetCustomPopupMenu(QPoint); + void decryptSelectedMsg() ; void changeBox(int newrow); void changeQuickView(int newrow); diff --git a/retroshare-gui/src/gui/NetworkDialog.cpp b/retroshare-gui/src/gui/NetworkDialog.cpp index a1842d89d..447802256 100644 --- a/retroshare-gui/src/gui/NetworkDialog.cpp +++ b/retroshare-gui/src/gui/NetworkDialog.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include "common/vmessagebox.h" #include "common/RSTreeWidgetItem.h" @@ -230,7 +231,10 @@ void NetworkDialog::connecttreeWidgetCostumPopupMenu( QPoint /*point*/ ) contextMnu->addAction(QIcon(IMAGE_PEERDETAILS), tr("Peer details..."), this, SLOT(peerdetails())); contextMnu->addAction(QIcon(IMAGE_COPYLINK), tr("Copy RetroShare Link"), this, SLOT(copyLink())); contextMnu->addSeparator() ; - +#ifdef ENABLE_DISTANT_CHAT_AND_MSGS + contextMnu->addAction(QIcon(IMAGE_COPYLINK), tr("Create a distant chat invitation..."), this, SLOT(createChatLink())); + contextMnu->addSeparator() ; +#endif contextMnu->addAction(QIcon(IMAGE_CLEAN_UNUSED), tr("Remove unused keys..."), this, SLOT(removeUnusedKeys())); contextMnu->exec(QCursor::pos()); @@ -330,6 +334,19 @@ void NetworkDialog::makeFriend() ConfCertDialog::showIt(getCurrentNeighbour()->text(COLUMN_PEERID).toStdString(), ConfCertDialog::PageTrust); } +void NetworkDialog::createChatLink() +{ + std::string pgp_id = getCurrentNeighbour()->text(COLUMN_PEERID).toStdString() ; + + std::cerr << "Creating chat link for pgp id " << pgp_id << std::endl; + + std::string hash,estr ; + rsMsgs->createDistantChatInvite(pgp_id,time(NULL)+3600,estr) ; + + std::cerr << "Created invite:" << std::endl; + std::cerr << " estr = " << estr << std::endl; +} + /** Shows Peer Information/Auth Dialog */ void NetworkDialog::peerdetails() { diff --git a/retroshare-gui/src/gui/NetworkDialog.h b/retroshare-gui/src/gui/NetworkDialog.h index 036b2cf30..b15228698 100644 --- a/retroshare-gui/src/gui/NetworkDialog.h +++ b/retroshare-gui/src/gui/NetworkDialog.h @@ -69,6 +69,7 @@ private slots: void removeUnusedKeys() ; void makeFriend() ; void denyFriend() ; + void createChatLink() ; void deleteCert() ; void peerdetails(); void copyLink(); diff --git a/retroshare-gui/src/gui/NewsFeed.cpp b/retroshare-gui/src/gui/NewsFeed.cpp index 5989411f6..28ee213c6 100644 --- a/retroshare-gui/src/gui/NewsFeed.cpp +++ b/retroshare-gui/src/gui/NewsFeed.cpp @@ -71,7 +71,7 @@ static NewsFeed *instance = NULL; /** Constructor */ NewsFeed::NewsFeed(QWidget *parent) -: MainPage (parent) +: RsAutoUpdatePage(1000,parent) { /* Invoke the Qt Designer generated object setup routine */ setupUi(this); @@ -83,9 +83,9 @@ NewsFeed::NewsFeed(QWidget *parent) connect(removeAllButton, SIGNAL(clicked()), this, SLOT(removeAll())); connect(feedOptionsButton, SIGNAL(clicked()), this, SLOT(feedoptions())); - QTimer *timer = new QTimer(this); - timer->connect(timer, SIGNAL(timeout()), this, SLOT(updateFeed())); - timer->start(1000); +// QTimer *timer = new QTimer(this); +// timer->connect(timer, SIGNAL(timeout()), this, SLOT(updateFeed())); +// timer->start(1000); } NewsFeed::~NewsFeed() @@ -95,7 +95,7 @@ NewsFeed::~NewsFeed() } } -void NewsFeed::updateFeed() +void NewsFeed::updateDisplay() { if (!rsNotify) return; diff --git a/retroshare-gui/src/gui/NewsFeed.h b/retroshare-gui/src/gui/NewsFeed.h index 958d9bc84..d97356224 100644 --- a/retroshare-gui/src/gui/NewsFeed.h +++ b/retroshare-gui/src/gui/NewsFeed.h @@ -26,6 +26,7 @@ #include "ui_NewsFeed.h" #include "gui/feeds/FeedHolder.h" +#include class RsFeedItem; class ForumNewItem; @@ -33,7 +34,7 @@ class ChanMsgItem; class ChatMsgItem; class FeedNotify; -class NewsFeed : public MainPage, public FeedHolder, private Ui::NewsFeed +class NewsFeed : public RsAutoUpdatePage, public FeedHolder, private Ui::NewsFeed { Q_OBJECT @@ -52,6 +53,7 @@ public: static void testFeeds(uint notifyFlags); static void testFeed(FeedNotify *feedNotify); + virtual void updateDisplay(); signals: void newsFeedChanged(int count); @@ -59,7 +61,6 @@ private slots: // void toggleChanMsgItems(bool on); void feedoptions(); - void updateFeed(); void removeAll(); void itemDestroyed(QObject*); diff --git a/retroshare-gui/src/gui/RetroShareLink.cpp b/retroshare-gui/src/gui/RetroShareLink.cpp index 48a3f7c34..34aa0eb9a 100644 --- a/retroshare-gui/src/gui/RetroShareLink.cpp +++ b/retroshare-gui/src/gui/RetroShareLink.cpp @@ -41,6 +41,7 @@ #include "gui/connect/ConfCertDialog.h" #include +#include #include #include #include @@ -55,7 +56,9 @@ #define HOST_MESSAGE "message" #define HOST_SEARCH "search" #define HOST_CERTIFICATE "certificate" -#define HOST_REGEXP "file|person|forum|channel|search|message|certificate" +#define HOST_PUBLIC_MSG "public_msg" +#define HOST_PRIVATE_CHAT "private_chat" +#define HOST_REGEXP "file|person|forum|channel|search|message|certificate|private_chat|public_msg" #define FILE_NAME "name" #define FILE_SIZE "size" @@ -87,6 +90,14 @@ #define CERTIFICATE_EXT_IPPORT "extipp" #define CERTIFICATE_LOC_IPPORT "locipp" +#define PRIVATE_CHAT_TIME_STAMP "time_stamp" +#define PRIVATE_CHAT_STRING "encrypted_data" +#define PRIVATE_CHAT_GPG_ID "gpgid" + +#define PUBLIC_MSG_TIME_STAMP "time_stamp" +#define PUBLIC_MSG_SRC_PGP_ID "gpgid" +#define PUBLIC_MSG_HASH "hash" + RetroShareLink::RetroShareLink(const QUrl& url) { fromUrl(url); @@ -107,7 +118,8 @@ void RetroShareLink::fromString(const QString& url) #endif if ((url.startsWith(QString(RSLINK_SCHEME) + "://" + QString(HOST_FILE)) && url.count("|") == 3) || - (url.startsWith(QString(RSLINK_SCHEME) + "://" + QString(HOST_PERSON)) && url.count("|") == 2)) { + (url.startsWith(QString(RSLINK_SCHEME) + "://" + QString(HOST_PERSON)) && url.count("|") == 2)) + { /* Old link, we try it */ QStringList list = url.split ("|"); @@ -158,6 +170,7 @@ void RetroShareLink::fromUrl(const QUrl& url) if (url.scheme() != RSLINK_SCHEME) { /* No RetroShare-Link */ + std::cerr << "Not a RS link: scheme=" << url.scheme().toStdString() << std::endl; return; } @@ -181,6 +194,29 @@ void RetroShareLink::fromUrl(const QUrl& url) } } + if(url.host() == HOST_PRIVATE_CHAT) + { + bool ok ; + _type = TYPE_PRIVATE_CHAT ; + _time_stamp = url.queryItemValue(PRIVATE_CHAT_TIME_STAMP).toUInt(&ok) ; + _encrypted_chat_info = url.queryItemValue(PRIVATE_CHAT_STRING) ; + _GPGid = url.queryItemValue(PRIVATE_CHAT_GPG_ID) ; + + check() ; + return; + } + if(url.host() == HOST_PUBLIC_MSG) + { + bool ok ; + _type = TYPE_PUBLIC_MSG ; + _hash = url.queryItemValue(PUBLIC_MSG_HASH) ; + _time_stamp = url.queryItemValue(PUBLIC_MSG_TIME_STAMP).toUInt(&ok) ; + _GPGid = url.queryItemValue(PUBLIC_MSG_SRC_PGP_ID) ; + + check() ; + return; + } + if (url.host() == HOST_EXTRAFILE) { bool ok ; @@ -299,6 +335,32 @@ bool RetroShareLink::createFile(const QString& name, uint64_t size, const QStrin return valid(); } +bool RetroShareLink::createPrivateChatInvite(time_t time_stamp,const QString& gpg_id,const QString& encrypted_chat_info) +{ + clear() ; + + _type = TYPE_PRIVATE_CHAT ; + _time_stamp = time_stamp ; + _encrypted_chat_info = encrypted_chat_info ; + _GPGid = gpg_id ; + + check() ; + + return valid() ; +} +bool RetroShareLink::createPublicMsgInvite(time_t time_stamp,const QString& issuer_pgp_id,const QString& hash) +{ + clear() ; + + _type = TYPE_PUBLIC_MSG ; + _time_stamp = time_stamp ; + _hash = hash ; + _GPGid = issuer_pgp_id ; + + check() ; + + return valid() ; +} bool RetroShareLink::createPerson(const std::string& id) { clear(); @@ -491,78 +553,93 @@ void RetroShareLink::clear() _hash = "" ; _size = 0 ; _name = "" ; + _GPGid = "" ; + _time_stamp = 0 ; + _encrypted_chat_info = "" ; } void RetroShareLink::check() { _valid = true; - switch (_type) { - case TYPE_UNKNOWN: - _valid = false; - break; - case TYPE_EXTRAFILE: - if(!checkSSLId(_SSLid)) - _valid = false; // no break! We also test file stuff below. - case TYPE_FILE: - if(_size > (((uint64_t)1)<<40)) // 1TB. Who has such large files? + switch (_type) + { + case TYPE_UNKNOWN: _valid = false; + break; + case TYPE_EXTRAFILE: + if(!checkSSLId(_SSLid)) + _valid = false; // no break! We also test file stuff below. + case TYPE_FILE: + if(_size > (((uint64_t)1)<<40)) // 1TB. Who has such large files? + _valid = false; - if(!checkName(_name)) - _valid = false; + if(!checkName(_name)) + _valid = false; - if(!checkHash(_hash)) - _valid = false; - break; - case TYPE_PERSON: - if(_size != 0) - _valid = false; + if(!checkHash(_hash)) + _valid = false; + break; - if(_name.isEmpty()) - _valid = false; + case TYPE_PRIVATE_CHAT: + if(!checkRadix64(_encrypted_chat_info)) _valid = false ; + if(!checkPGPId(_GPGid)) _valid = false ; + break ; - if(_hash.isEmpty()) - _valid = false; - break; - case TYPE_FORUM: - if(_size != 0) - _valid = false; + case TYPE_PUBLIC_MSG: + if(!checkHash(_hash)) _valid = false ; + if(!checkPGPId(_GPGid)) _valid = false ; + break ; - if(_name.isEmpty()) - _valid = false; + case TYPE_PERSON: + if(_size != 0) + _valid = false; - if(_hash.isEmpty()) - _valid = false; - break; - case TYPE_CHANNEL: - if(_size != 0) - _valid = false; + if(_name.isEmpty()) + _valid = false; - if(_name.isEmpty()) - _valid = false; + if(_hash.isEmpty()) + _valid = false; + break; + case TYPE_FORUM: + if(_size != 0) + _valid = false; - if(_hash.isEmpty()) - _valid = false; - break; - case TYPE_SEARCH: - if(_size != 0) - _valid = false; + if(_name.isEmpty()) + _valid = false; - if(_name.isEmpty()) - _valid = false; + if(_hash.isEmpty()) + _valid = false; + break; + case TYPE_CHANNEL: + if(_size != 0) + _valid = false; - if(!_hash.isEmpty()) - _valid = false; - break; - case TYPE_MESSAGE: - if(_size != 0) - _valid = false; + if(_name.isEmpty()) + _valid = false; - if(_hash.isEmpty()) - _valid = false; - break; - case TYPE_CERTIFICATE: - break; + if(_hash.isEmpty()) + _valid = false; + break; + case TYPE_SEARCH: + if(_size != 0) + _valid = false; + + if(_name.isEmpty()) + _valid = false; + + if(!_hash.isEmpty()) + _valid = false; + break; + case TYPE_MESSAGE: + if(_size != 0) + _valid = false; + + if(_hash.isEmpty()) + _valid = false; + break; + case TYPE_CERTIFICATE: + break; } if (!_valid) { @@ -579,6 +656,22 @@ QString RetroShareLink::title() const switch (_type) { case TYPE_UNKNOWN: break; + case TYPE_PUBLIC_MSG: + { + RsPeerDetails detail; + rsPeers->getPeerDetails(_GPGid.toStdString(), detail) ; + return QString("Click to send a private message to %1 (%2).").arg(QString::fromStdString(detail.name)).arg(_GPGid) ; + } + case TYPE_PRIVATE_CHAT: + { + RsPeerDetails detail; + rsPeers->getPeerDetails(_GPGid.toStdString(), detail) ; + + if (_GPGid.toStdString() == rsPeers->getGPGOwnId()) + return QString("Click to open a private chat canal to %1 (%2).").arg(QString::fromStdString(detail.name)).arg(_GPGid) ; + else + return QString("This is a private chat invite for %1 (%2). You can't use it.").arg(QString::fromStdString(detail.name)).arg(_GPGid) ; + } case TYPE_EXTRAFILE: return QString("%1 (%2, Extra - Source included)").arg(hash()).arg(misc::friendlyUnit(size())); case TYPE_FILE: @@ -619,6 +712,29 @@ QString RetroShareLink::toString() const return url.toString(); } + case TYPE_PRIVATE_CHAT: + { + QUrl url; + url.setScheme(RSLINK_SCHEME) ; + url.setHost(HOST_PRIVATE_CHAT) ; + url.addQueryItem(PRIVATE_CHAT_TIME_STAMP,QString::number(_time_stamp)) ; + url.addQueryItem(PRIVATE_CHAT_GPG_ID,_GPGid) ; + url.addQueryItem(PRIVATE_CHAT_STRING,_encrypted_chat_info) ; + + return url.toString() ; + } + case TYPE_PUBLIC_MSG: + { + QUrl url; + url.setScheme(RSLINK_SCHEME) ; + url.setHost(HOST_PUBLIC_MSG) ; + url.addQueryItem(PUBLIC_MSG_TIME_STAMP,QString::number(_time_stamp)) ; + url.addQueryItem(PUBLIC_MSG_HASH,_hash) ; + url.addQueryItem(PUBLIC_MSG_SRC_PGP_ID,_GPGid) ; + + return url.toString() ; + } + case TYPE_EXTRAFILE: { QUrl url; @@ -724,6 +840,14 @@ QString RetroShareLink::niceName() const return PeerDefs::rsid(name().toUtf8().constData(), hash().toStdString()); } + if(type() == TYPE_PRIVATE_CHAT) { + return QString("Private chat invite (Valid only for key %1)").arg(_GPGid); + } + if(type() == TYPE_PUBLIC_MSG) { + RsPeerDetails detail; + rsPeers->getPeerDetails(_GPGid.toStdString(), detail) ; + return QString("Click this link to send a private message to %1 (%2)").arg(QString::fromStdString(detail.name)).arg(_GPGid) ; + } if(type() == TYPE_CERTIFICATE) { if (_location.isEmpty()) { return QString("RetroShare Certificate (%1)").arg(_name); @@ -814,6 +938,41 @@ bool RetroShareLink::checkSSLId(const QString& ssl_id) return true ; } +bool RetroShareLink::checkPGPId(const QString& pgp_id) +{ + if(pgp_id.length() != 16) + return false ; + + QByteArray qb(pgp_id.toAscii()) ; + + for(int i=0;i47 && b<58) || (b>64 && b<71))) + return false ; + } + + return true ; +} +bool RetroShareLink::checkRadix64(const QString& s) +{ + QByteArray qb(s.toAscii()) ; + + for(int i=0;i 46 && b < 58) || (b > 64 && b < 91) || (b > 96 && b < 123) || b=='+' || b=='=')) + { + std::cerr << "Character not allowed in radix: " << b << std::endl; + return false; + } + } + std::cerr << "Radix check: passed" << std::endl; + return true ; +} + bool RetroShareLink::checkHash(const QString& hash) { if(hash.length() != 40) @@ -1028,6 +1187,58 @@ static void processList(const QStringList &list, const QString &textSingular, co } break ; + case TYPE_PUBLIC_MSG: + { + std::cerr << "Opening a public msg window " << std::endl; + std::cerr << " time_stamp = " << link._time_stamp << std::endl; + std::cerr << " hash = " << link._hash.toStdString() << std::endl; + std::cerr << " Issuer Id = " << link._GPGid.toStdString() << std::endl; + + if(link._time_stamp < time(NULL)) + { + QMessageBox::information(NULL,QObject::tr("Messenging link is expired"),QObject::tr("This Messenging link is expired. The destination peer will not receive it.")) ; + break ; + } + + MessageComposer::msgDistantPeer(link._hash.toStdString(),link._GPGid.toStdString()) ; + } + break ; + case TYPE_PRIVATE_CHAT: + { + std::cerr << "Opening a private chat window " << std::endl; + std::cerr << " time_stamp = " << link._time_stamp << std::endl; + std::cerr << " enc-string = " << link._encrypted_chat_info.toStdString() << std::endl; + std::cerr << " PGP Id = " << link._GPGid.toStdString() << std::endl; + + if(link._time_stamp < time(NULL)) + { + QMessageBox::information(NULL,QObject::tr("Chat link is expired"),QObject::tr("This chat link is expired. The destination peer will not answer.")) ; + break ; + } + if(link._GPGid.toStdString() != rsPeers->getGPGOwnId()) + { + QMessageBox::information(NULL,QObject::tr("Chat link cannot be decrypted"),QObject::tr("This chat link is encrypted with a key that is not yours. You can't used it. Key ID = ")+link._GPGid) ; + break ; + } + + std::string hash ; + uint32_t error_code ; + + if(!rsMsgs->initiateDistantChatConnexion(link._encrypted_chat_info.toStdString(),hash,error_code)) + { + QString error_msg ; + switch(error_code) + { + default: + case RS_DISTANT_CHAT_ERROR_DECRYPTION_FAILED: error_msg = QObject::tr("The link could not be decrypted.") ; break ; + case RS_DISTANT_CHAT_ERROR_SIGNATURE_MISMATCH: error_msg = QObject::tr("The link signature cannot be checked.") ; break ; + case RS_DISTANT_CHAT_ERROR_UNKNOWN_KEY: error_msg = QObject::tr("The link is signed by an unknown key.") ; break ; + } + QMessageBox::information(NULL,QObject::tr("Chat connexion is not possible"),error_msg) ; + } + } + break ; + case TYPE_FILE: case TYPE_EXTRAFILE: { diff --git a/retroshare-gui/src/gui/RetroShareLink.h b/retroshare-gui/src/gui/RetroShareLink.h index 2cb2a0c81..7d163354a 100644 --- a/retroshare-gui/src/gui/RetroShareLink.h +++ b/retroshare-gui/src/gui/RetroShareLink.h @@ -52,7 +52,18 @@ class RetroShareLink { public: - enum enumType { TYPE_UNKNOWN, TYPE_FILE, TYPE_PERSON, TYPE_FORUM, TYPE_CHANNEL, TYPE_SEARCH, TYPE_MESSAGE, TYPE_CERTIFICATE,TYPE_EXTRAFILE }; + enum enumType { TYPE_UNKNOWN = 0x00, + TYPE_FILE = 0x01, + TYPE_PERSON = 0x02, + TYPE_FORUM = 0x03, + TYPE_CHANNEL = 0x04, + TYPE_SEARCH = 0x05, + TYPE_MESSAGE = 0x06, + TYPE_CERTIFICATE = 0x07, + TYPE_EXTRAFILE = 0x08, + TYPE_PRIVATE_CHAT = 0x09, + TYPE_PUBLIC_MSG = 0x0a + }; public: RetroShareLink(); @@ -67,6 +78,8 @@ class RetroShareLink bool createSearch(const QString& keywords); bool createMessage(const std::string& peerId, const QString& subject); bool createCertificate(const std::string& ssl_or_gpg_id) ; + bool createPrivateChatInvite(time_t time_stamp,const QString& gpg_id,const QString& encrypted_chat_info) ; + bool createPublicMsgInvite(time_t time_stamp,const QString& pgp_id,const QString& hash) ; bool createUnknwonSslCertificate(const std::string& sslId, const std::string& gpgId = "") ; enumType type() const {return _type; } @@ -83,6 +96,8 @@ class RetroShareLink const QString& localIPAndPort() const { return _loc_ip_port ; } const QString& externalIPAndPort() const { return _ext_ip_port ; } const QString& location() const { return _location ; } + const time_t timeStamp() const { return _time_stamp ; } + const QString& encryptedPrivateChatInfo() const { return _encrypted_chat_info ; } QString title() const; unsigned int subType() const { return _subType; } @@ -118,8 +133,10 @@ class RetroShareLink void clear(); void check(); static bool checkHash(const QString& hash); + static bool checkRadix64(const QString& s); static bool checkName(const QString& name); static bool checkSSLId(const QString& name); + static bool checkPGPId(const QString& name); bool _valid; enumType _type; @@ -135,6 +152,9 @@ class RetroShareLink QString _location ; // location QString _ext_ip_port ; QString _loc_ip_port ; + QString _encrypted_chat_info ; // encrypted data string for the recipient of a chat invite + time_t _time_stamp ; // time stamp at which the link will expire. + unsigned int _subType; // for general use as sub type for _type (RSLINK_SUBTYPE_...) }; diff --git a/retroshare-gui/src/gui/chat/ChatDialog.cpp b/retroshare-gui/src/gui/chat/ChatDialog.cpp index 45738b92d..d4f55869a 100644 --- a/retroshare-gui/src/gui/chat/ChatDialog.cpp +++ b/retroshare-gui/src/gui/chat/ChatDialog.cpp @@ -26,6 +26,7 @@ #include "ChatDialog.h" #include "gui/common/PeerDefs.h" #include "PopupChatDialog.h" +#include "PopupDistantChatDialog.h" #include "ChatLobbyDialog.h" #include "PopupChatWindow.h" #include "gui/settings/rsharesettings.h" @@ -91,11 +92,19 @@ void ChatDialog::init(const std::string &peerId, const QString &title) ChatDialog *cd = getExistingChat(peerId); if (cd == NULL) { - ChatLobbyId lobby_id; + ChatLobbyId lobby_id = 0; + bool distant_peer = false ; + if (rsMsgs->isLobbyId(peerId, lobby_id)) { chatflags = RS_CHAT_OPEN | RS_CHAT_FOCUS; // use own flags } + uint32_t distant_peer_status ; + std::string distant_chat_pgp_id ; + + if(rsMsgs->getDistantChatStatus(peerId,distant_peer_status,distant_chat_pgp_id)) + chatflags = RS_CHAT_OPEN | RS_CHAT_FOCUS; // use own flags + if (chatflags & RS_CHAT_OPEN) { if (lobby_id) { std::list linfos; @@ -108,6 +117,12 @@ void ChatDialog::init(const std::string &peerId, const QString &title) cd->init(peerId, QString::fromUtf8((*it).lobby_name.c_str())); } } + } else if(distant_peer_status > 0) { + cd = new PopupDistantChatDialog(); + chatDialogs[peerId] = cd; + std::string peer_name = rsPeers->getGPGName(distant_chat_pgp_id) ; + cd->init(peerId, tr("Talking to ")+QString::fromStdString(peer_name)+" (PGP id="+QString::fromStdString(distant_chat_pgp_id)+")") ; + } else { RsPeerDetails sslDetails; if (rsPeers->getPeerDetails(peerId, sslDetails)) { diff --git a/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp b/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp index e4f699ce2..7d4ae2c52 100644 --- a/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp +++ b/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp @@ -78,7 +78,7 @@ ChatLobbyDialog::ChatLobbyDialog(const ChatLobbyId& lid, QWidget *parent, Qt::WF connect(inviteFriendsButton, SIGNAL(clicked()), this , SLOT(inviteFriends())); - getChatWidget()->addChatButton(inviteFriendsButton) ; + getChatWidget()->addChatBarWidget(inviteFriendsButton) ; unsubscribeButton = new QPushButton ; unsubscribeButton->setMinimumSize(QSize(28,28)) ; @@ -95,7 +95,7 @@ ChatLobbyDialog::ChatLobbyDialog(const ChatLobbyId& lid, QWidget *parent, Qt::WF connect(unsubscribeButton, SIGNAL(clicked()), this , SLOT(leaveLobby())); - getChatWidget()->addChatButton(unsubscribeButton) ; + getChatWidget()->addChatBarWidget(unsubscribeButton) ; } void ChatLobbyDialog::leaveLobby() diff --git a/retroshare-gui/src/gui/chat/ChatWidget.cpp b/retroshare-gui/src/gui/chat/ChatWidget.cpp index 2992d5ff6..64dcb1fef 100644 --- a/retroshare-gui/src/gui/chat/ChatWidget.cpp +++ b/retroshare-gui/src/gui/chat/ChatWidget.cpp @@ -36,6 +36,7 @@ #include "ui_ChatWidget.h" #include "gui/notifyqt.h" #include "gui/RetroShareLink.h" +#include "gui/CreateMsgLinkDialog.h" #include "gui/settings/rsharesettings.h" #include "gui/settings/RsharePeerSettings.h" #include "gui/im_history/ImHistoryBrowser.h" @@ -139,9 +140,9 @@ void ChatWidget::setDefaultExtraFileFlags(TransferRequestFlags fl) ui->hashBox->setDefaultTransferRequestFlags(fl) ; } -void ChatWidget::addChatButton(QPushButton *button) +void ChatWidget::addChatBarWidget(QWidget *w) { - ui->toolBarFrame->layout()->addWidget(button) ; + ui->toolBarFrame->layout()->addWidget(w) ; } void ChatWidget::init(const std::string &peerId, const QString &title) @@ -548,11 +549,22 @@ void ChatWidget::contextMenu(QPoint point) QAction *action = contextMnu->addAction(QIcon(":/images/pasterslink.png"), tr("Paste RetroShare Link"), this, SLOT(pasteLink())); action->setDisabled(RSLinkClipboard::empty()); contextMnu->addAction(QIcon(":/images/pasterslink.png"), tr("Paste my certificate link"), this, SLOT(pasteOwnCertificateLink())); +#ifdef ENABLE_DISTANT_CHAT_AND_MSGS + contextMnu->addAction(QIcon(":/images/pasterslink.png"), tr("Paste/Create private chat or Message link..."), this, SLOT(pasteCreateMsgLink())); +#endif contextMnu->exec(QCursor::pos()); delete(contextMnu); } +void ChatWidget::pasteCreateMsgLink() +{ + CreateMsgLinkDialog dialog ; + dialog.exec() ; + + ui->chatTextEdit->insertHtml(RSLinkClipboard::toHtml()); +} + void ChatWidget::contextMenuTextBrowser(QPoint point) { QMatrix matrix; diff --git a/retroshare-gui/src/gui/chat/ChatWidget.h b/retroshare-gui/src/gui/chat/ChatWidget.h index 39d28c29f..a7aff6b15 100644 --- a/retroshare-gui/src/gui/chat/ChatWidget.h +++ b/retroshare-gui/src/gui/chat/ChatWidget.h @@ -47,7 +47,6 @@ class ChatWidget : public QWidget public: enum enumChatType { TYPE_NORMAL, TYPE_HISTORY, TYPE_OFFLINE, TYPE_SYSTEM }; -public: explicit ChatWidget(QWidget *parent = 0); ~ChatWidget(); @@ -74,13 +73,14 @@ public: bool setStyle(); const RSStyle *getStyle() { return &style; } - void addChatButton(QPushButton *button) ; + void addChatBarWidget(QWidget *w) ; bool isActive(); void setDefaultExtraFileFlags(TransferRequestFlags f) ; void pasteText(const QString&); private slots: + void pasteCreateMsgLink() ; void clearChatHistory(); void deleteChatHistory(); void messageHistory(); diff --git a/retroshare-gui/src/gui/chat/PopupChatDialog.cpp b/retroshare-gui/src/gui/chat/PopupChatDialog.cpp index 9c4afeb50..1692ad048 100644 --- a/retroshare-gui/src/gui/chat/PopupChatDialog.cpp +++ b/retroshare-gui/src/gui/chat/PopupChatDialog.cpp @@ -141,9 +141,9 @@ void PopupChatDialog::addIncomingChatMsg(const ChatInfo& info) } } -void PopupChatDialog::addButton(QPushButton *button) +void PopupChatDialog::addChatBarWidget(QWidget *w) { - getChatWidget()->addChatButton(button) ; + getChatWidget()->addChatBarWidget(w) ; } void PopupChatDialog::onChatChanged(int list, int type) diff --git a/retroshare-gui/src/gui/chat/PopupChatDialog.h b/retroshare-gui/src/gui/chat/PopupChatDialog.h index 620d84afc..a53aa24dd 100644 --- a/retroshare-gui/src/gui/chat/PopupChatDialog.h +++ b/retroshare-gui/src/gui/chat/PopupChatDialog.h @@ -57,7 +57,7 @@ protected: void processSettings(bool load); // used by plugins - void addButton(QPushButton *button) ; + void addChatBarWidget(QWidget *w) ; protected: virtual void addIncomingChatMsg(const ChatInfo& info); diff --git a/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp b/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp new file mode 100644 index 000000000..8bde8fdd0 --- /dev/null +++ b/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp @@ -0,0 +1,98 @@ +/**************************************************************** + * RetroShare is distributed under the following license: + * + * Copyright (C) 2013, Cyril Soler + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + ****************************************************************/ + +#include +#include "PopupDistantChatDialog.h" + +#define IMAGE_RED_LED ":/images/redled.png" +#define IMAGE_YEL_LED ":/images/yellowled.png" +#define IMAGE_GRN_LED ":/images/greenled.png" +#define IMAGE_GRY_LED ":/images/grayled.png" + +PopupDistantChatDialog::~PopupDistantChatDialog() +{ + delete _tunnel_check_timer ; +} + +PopupDistantChatDialog::PopupDistantChatDialog(QWidget *parent, Qt::WFlags flags) + : PopupChatDialog(parent,flags) +{ + _tunnel_check_timer = new QTimer; + _tunnel_check_timer->setInterval(1000) ; + + QObject::connect(_tunnel_check_timer,SIGNAL(timeout()),this,SLOT(checkTunnel())) ; + + _tunnel_check_timer->start() ; + _status_label = new QLabel ; + + addChatBarWidget(_status_label) ; + checkTunnel() ; +} + +void PopupDistantChatDialog::init(const std::string& hash,const QString & title) +{ + _hash = hash ; + PopupChatDialog::init(hash,title) ; +} + +void PopupDistantChatDialog::checkTunnel() +{ + if(!isVisible()) + return ; + + std::cerr << "Checking tunnel..." ; + // make sure about the tunnel status + // + + uint32_t status= RS_DISTANT_CHAT_STATUS_UNKNOWN; + std::string pgp_id ; + rsMsgs->getDistantChatStatus(_hash,status,pgp_id) ; + + switch(status) + { + case RS_DISTANT_CHAT_STATUS_UNKNOWN: std::cerr << "Unknown hash. Error!" << std::endl; + _status_label->setPixmap(QPixmap(IMAGE_GRY_LED)) ; + _status_label->setToolTip(tr("Hash error")) ; + break ; + case RS_DISTANT_CHAT_STATUS_TUNNEL_DN: std::cerr << "Tunnel asked. Waiting for reponse. " << std::endl; + _status_label->setPixmap(QPixmap(IMAGE_RED_LED)) ; + _status_label->setToolTip(tr("Tunnel is broken")) ; + break ; + case RS_DISTANT_CHAT_STATUS_TUNNEL_OK: std::cerr << "Tunnel is ok. " << std::endl; + _status_label->setPixmap(QPixmap(IMAGE_YEL_LED)) ; + _status_label->setToolTip(tr("Tunnel established")) ; + break ; + case RS_DISTANT_CHAT_STATUS_CAN_TALK: std::cerr << "Tunnel is ok and works. You can talk!" << std::endl; + _status_label->setPixmap(QPixmap(IMAGE_GRN_LED)) ; + _status_label->setToolTip(tr("Tunnel is working")) ; + break ; + } +} + + + + + + + + + + diff --git a/retroshare-gui/src/gui/chat/PopupDistantChatDialog.h b/retroshare-gui/src/gui/chat/PopupDistantChatDialog.h new file mode 100644 index 000000000..a67c7ba1a --- /dev/null +++ b/retroshare-gui/src/gui/chat/PopupDistantChatDialog.h @@ -0,0 +1,53 @@ + +/**************************************************************** + * RetroShare is distributed under the following license: + * + * Copyright (C) 2013, Cyril Soler + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + ****************************************************************/ + +#pragma once + +#include "PopupChatDialog.h" + +class QTimer ; + +class PopupDistantChatDialog: public PopupChatDialog +{ + Q_OBJECT + + friend class ChatDialog; + + public slots: + void checkTunnel() ; + +protected: + /** Default constructor */ + PopupDistantChatDialog(QWidget *parent = 0, Qt::WFlags flags = 0); + /** Default destructor */ + virtual ~PopupDistantChatDialog(); + + virtual void init(const std::string& _hash, const QString &title); + virtual void updateStatus(int /*status*/) {} + + QTimer *_tunnel_check_timer ; + std::string _hash ; + std::string _virtual_peer_id ; + QLabel *_status_label ; +}; + + diff --git a/retroshare-gui/src/gui/msgs/MessageComposer.cpp b/retroshare-gui/src/gui/msgs/MessageComposer.cpp index 283b71e0d..4a360034d 100644 --- a/retroshare-gui/src/gui/msgs/MessageComposer.cpp +++ b/retroshare-gui/src/gui/msgs/MessageComposer.cpp @@ -352,6 +352,22 @@ void MessageComposer::processSettings(bool bLoad) Settings->endGroup(); } +/*static*/ void MessageComposer::msgDistantPeer(const std::string& hash,const std::string& pgp_id) +{ +// std::cerr << "MessageComposer::msgfriend()" << std::endl; + + /* create a message */ + + MessageComposer *pMsgDialog = MessageComposer::newMsg(); + if (pMsgDialog == NULL) + return; + + pMsgDialog->addRecipient(TO, hash,pgp_id) ; + pMsgDialog->show(); + + /* window will destroy itself! */ +} + /*static*/ void MessageComposer::msgFriend(const std::string &id, bool group) { @@ -1219,7 +1235,7 @@ bool MessageComposer::sendMessage_internal(bool bDraftbox) } } } else { - if (std::find(peers.begin(), peers.end(), id) == peers.end()) { + if (_distant_peers.find(id)==_distant_peers.end() && std::find(peers.begin(), peers.end(), id) == peers.end()) { // no friend continue; } @@ -1269,6 +1285,7 @@ bool MessageComposer::sendMessage_internal(bool bDraftbox) QMessageBox::warning(this, tr("RetroShare"), tr("Please insert at least one recipient."), QMessageBox::Ok); return false; // Don't send with no recipient } + mi.encryption_keys = _distant_peers ; if (rsMsgs->MessageSend(mi) == false) { return false; @@ -1402,7 +1419,13 @@ void MessageComposer::setRecipientToRow(int row, enumType type, std::string id, } } else { RsPeerDetails details; - if (rsPeers->getPeerDetails(id, details)) { + if(_distant_peers.find(id) != _distant_peers.end()) + { + name = tr("Distant peer (PGP key: %1)").arg(QString::fromStdString(_distant_peers[id])) ; + icon = QIcon(StatusDefs::imageUser(RS_STATUS_ONLINE)); + } + else if (rsPeers->getPeerDetails(id, details)) + { name = PeerDefs::nameWithLocation(details); StatusInfo peerStatusInfo; @@ -1546,6 +1569,32 @@ void MessageComposer::editingRecipientFinished() lineEdit->setText(text); } +void MessageComposer::addRecipient(enumType type, const std::string& hash,const std::string& pgp_id) +{ + _distant_peers[hash] = pgp_id ; + + int rowCount = ui.recipientWidget->rowCount(); + int row; + for (row = 0; row < rowCount; row++) + { + enumType rowType; + std::string rowId; + bool rowGroup; + + if (getRecipientFromRow(row, rowType, rowId, rowGroup) == true) + { + if (rowId.empty()) // use row + break; + + if (rowId == hash && rowType == type) // existing row + break; + } + else // use row + break; + } + + setRecipientToRow(row, type, hash, false); +} void MessageComposer::addRecipient(enumType type, const std::string &id, bool group) { std::list sslIds; diff --git a/retroshare-gui/src/gui/msgs/MessageComposer.h b/retroshare-gui/src/gui/msgs/MessageComposer.h index bc9faa4e1..f5aa98bee 100644 --- a/retroshare-gui/src/gui/msgs/MessageComposer.h +++ b/retroshare-gui/src/gui/msgs/MessageComposer.h @@ -49,6 +49,8 @@ public: ~MessageComposer(); static void msgFriend(const std::string &id, bool group); + static void msgDistantPeer(const std::string& hash,const std::string& pgp_id) ; + static QString recommendMessage(); static void recommendFriend(const std::list &sslIds, const std::string &to = "", const QString &msg = "", bool autoSend = false); static void sendConnectAttemptMsg(const std::string &gpgId, const std::string &sslId, const QString &sslName); @@ -65,6 +67,7 @@ public: void setQuotedMsg(const QString &msg, const QString &header); void setMsgText(const QString &msg, bool asHtml = false); void addRecipient(enumType type, const std::string &id, bool group); + void addRecipient(enumType type, const std::string &hash, const std::string& pgp_id) ; public slots: /* actions to take.... */ @@ -217,6 +220,7 @@ private: Ui::MessageComposer ui; std::list _recList ; + std::map _distant_peers ; // pairs (hash,pgp_id) }; #endif diff --git a/retroshare-gui/src/retroshare-gui.pro b/retroshare-gui/src/retroshare-gui.pro index d7662c0d3..ce6c9e936 100644 --- a/retroshare-gui/src/retroshare-gui.pro +++ b/retroshare-gui/src/retroshare-gui.pro @@ -275,6 +275,7 @@ HEADERS += rshare.h \ gui/TurtleRouterStatistics.h \ gui/AboutDialog.h \ gui/ForumsDialog.h \ + gui/CreateMsgLinkDialog.h \ gui/forums/ForumDetails.h \ gui/forums/EditForumDetails.h \ gui/forums/CreateForum.h \ @@ -333,6 +334,7 @@ HEADERS += rshare.h \ gui/profile/StatusMessage.h \ gui/chat/PopupChatWindow.h \ gui/chat/PopupChatDialog.h \ + gui/chat/PopupDistantChatDialog.h \ gui/chat/ChatTabWidget.h \ gui/chat/ChatWidget.h \ gui/chat/ChatDialog.h \ @@ -471,6 +473,7 @@ FORMS += gui/StartDialog.ui \ gui/MainWindow.ui \ gui/TurtleRouterDialog.ui \ gui/TurtleRouterStatistics.ui \ + gui/CreateMsgLinkDialog.ui \ gui/forums/CreateForum.ui \ gui/forums/CreateForumMsg.ui \ gui/forums/ForumDetails.ui \ @@ -580,6 +583,7 @@ SOURCES += main.cpp \ gui/TurtleRouterStatistics.cpp \ gui/MainWindow.cpp \ gui/ForumsDialog.cpp \ + gui/CreateMsgLinkDialog.cpp \ gui/forums/ForumDetails.cpp \ gui/forums/EditForumDetails.cpp \ gui/forums/CreateForum.cpp \ @@ -642,6 +646,7 @@ SOURCES += main.cpp \ gui/channels/ChannelUserNotify.cpp \ gui/chat/PopupChatWindow.cpp \ gui/chat/PopupChatDialog.cpp \ + gui/chat/PopupDistantChatDialog.cpp \ gui/chat/ChatTabWidget.cpp \ gui/chat/ChatWidget.cpp \ gui/chat/ChatDialog.cpp \