From cb8b814543ee800ae4d7d15cbd5fac5c2a00acd3 Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 17 Nov 2015 18:11:00 -0500 Subject: [PATCH 01/26] added gxs tunnel service, based on distant chat code. Does not compile yet --- libretroshare/src/gxstunnel/p3gxstunnel.cc | 1092 +++++++++++++ libretroshare/src/gxstunnel/p3gxstunnel.h | 138 ++ .../src/gxstunnel/rsgxstunnelitems.cc | 1362 +++++++++++++++++ .../src/gxstunnel/rsgxstunnelitems.h | 430 ++++++ libretroshare/src/libretroshare.pro | 8 + 5 files changed, 3030 insertions(+) create mode 100644 libretroshare/src/gxstunnel/p3gxstunnel.cc create mode 100644 libretroshare/src/gxstunnel/p3gxstunnel.h create mode 100644 libretroshare/src/gxstunnel/rsgxstunnelitems.cc create mode 100644 libretroshare/src/gxstunnel/rsgxstunnelitems.h diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.cc b/libretroshare/src/gxstunnel/p3gxstunnel.cc new file mode 100644 index 000000000..a62e8e5b2 --- /dev/null +++ b/libretroshare/src/gxstunnel/p3gxstunnel.cc @@ -0,0 +1,1092 @@ +/* + * libretroshare/src/chat: distantchat.cc + * + * Services for RetroShare. + * + * Copyright 2014 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 "openssl/rand.h" +#include "openssl/dh.h" +#include "openssl/err.h" + +#include "util/rsaes.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include "p3gxstunnel.h" + +#define DEBUG_GXS_TUNNEL + +static const uint32_t GXS_TUNNEL_KEEP_ALIVE_TIMEOUT = 6 ; // send keep alive packet so as to avoid tunnel breaks. + +static const uint32_t RS_GXS_TUNNEL_DH_STATUS_UNINITIALIZED = 0x0000 ; +static const uint32_t RS_GXS_TUNNEL_DH_STATUS_HALF_KEY_DONE = 0x0001 ; +static const uint32_t RS_GXS_TUNNEL_DH_STATUS_KEY_AVAILABLE = 0x0002 ; + +void p3GxsTunnelService::connectToTurtleRouter(p3turtle *tr) +{ + mTurtle = tr ; + tr->registerTunnelService(this) ; +} + +void p3GxsTunnelService::flush() +{ + // Flush items that could not be sent, probably because of a Mutex protected zone. + // + while(!pendingGxsTunnelItems.empty()) + { + sendTurtleData( pendingGxsTunnelItems.front() ) ; + pendingGxsTunnelItems.pop_front() ; + } + + // TODO: also sweep GXS id map and disable any ID with no virtual peer id in the list. + + RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + + time_t now = time(NULL) ; + + for(std::map::iterator it(_gxs_tunnel_contacts.begin());it!=_gxs_tunnel_contacts.end();++it) + { + if(it->second.last_contact+20+GXS_TUNNEL_KEEP_ALIVE_TIMEOUT < now && it->second.status == RS_GXS_TUNNEL_STATUS_CAN_TALK) + { + std::cerr << "(II) GxsTunnelService:: connexion interrupted with peer." << std::endl; + it->second.status = RS_GXS_TUNNEL_STATUS_TUNNEL_DN ; + it->second.virtual_peer_id.clear() ; + + // Also reset turtle router monitoring so as to make the tunnel handling more responsive. If we don't do that, + // the TR will wait 60 secs for the tunnel to die, which causes a significant waiting time in the chat window. + + if(it->second.direction == RsTurtleGenericTunnelItem::DIRECTION_SERVER) + { + std::cerr << "(II) GxsTunnelService:: forcing new tunnel campain." << std::endl; + + mTurtle->forceReDiggTunnels( hashFromGxsId(it->first) ); + } + } + if(it->second.last_keep_alive_sent + GXS_TUNNEL_KEEP_ALIVE_TIMEOUT < now && it->second.status == RS_GXS_TUNNEL_STATUS_CAN_TALK) + { + RsChatStatusItem *cs = new RsChatStatusItem ; + +#warning should we send that unencrypted?? + cs->status_string.clear() ; + cs->flags = RS_CHAT_FLAG_PRIVATE | RS_CHAT_FLAG_KEEP_ALIVE; + cs->PeerId(RsPeerId(it->first)) ; + + // we send off-mutex to avoid deadlock. + + pendingGxsTunnelItems.push_back(cs) ; + + it->second.last_keep_alive_sent = now ; +#ifdef DEBUG_GXS_TUNNEL + std::cerr << "(II) GxsTunnelService:: Sending keep alive packet to gxs id " << it->first << std::endl; +#endif + } + } +} + +bool p3GxsTunnelService::handleRecvItem(RsChatItem *item) +{ + if(item == NULL) + return false ; + + switch(item->PacketSubType()) + { + case RS_PKT_SUBTYPE_GXS_TUNNEL_DH_PUBLIC_KEY: handleRecvDHPublicKey(dynamic_cast(item)) ; break ; + return true ; + + case RS_PKT_SUBTYPE_GXS_TUNNEL_STATUS: + { + // Keep alive packets should not be forwarded to the GUI. It's just for keeping the tunnel up. + + return true ; + } + + default: + return false ; + } + + return false ; +} +bool p3GxsTunnelService::handleOutgoingItem(RsChatItem *item) +{ + { + RS_STACK_MUTEX(mGxsTunnelMtx) ; + + std::map::const_iterator it=_gxs_tunnel_contacts.find(RsGxsId(item->PeerId())); + + if(it == _gxs_tunnel_contacts.end()) + return false ; + } + +#ifdef CHAT_DEBUG + std::cerr << "p3ChatService::handleOutgoingItem(): sending to " << item->PeerId() << ": interpreted as a distant chat virtual peer id." << std::endl; +#endif + sendTurtleData(item) ; + return true; +} + +void p3GxsTunnelService::handleRecvStatusItem(RsGxsTunnelStatusItem *cs) +{ + if(cs->flags & RS_GXS_TUNNEL_FLAG_CLOSING_DISTANT_CONNECTION) + markGxsTunnelAsClosed(RsGxsId(cs->PeerId())) ; + + // nothing more to do, because the decryption routing will update the last_contact time when decrypting. + + if(cs->flags & RS_GXS_TUNNEL_FLAG_KEEP_ALIVE) + std::cerr << "GxsTunnelService::handleRecvChatStatusItem(): received keep alive packet for inactive tunnel! peerId=" << cs->PeerId() << std::endl; +} + +bool p3GxsTunnelService::handleTunnelRequest(const RsFileHash& hash,const RsPeerId& /*peer_id*/) +{ + RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + + // look into owned GXS ids, and see if the hash corresponds to the expected hash + // + std::list own_id_list ; + rsIdentity->getOwnIds(own_id_list) ; + + // re-computing the hash from the GXS id allows to dynamically change the hash. That will allow + // the use of a contact passphrase, if needed. + + for(std::list::const_iterator it(own_id_list.begin());it!=own_id_list.end();++it) + if(hashFromGxsId(*it) == hash) + { +#ifdef DEBUG_GXS_TUNNEL + std::cerr << "GxsTunnelService::handleTunnelRequest: received tunnel request for hash " << hash << std::endl; + std::cerr << " answering true!" << std::endl; +#endif + return true ; + } + + return false ; +} + +void p3GxsTunnelService::addVirtualPeer(const TurtleFileHash& hash,const TurtleVirtualPeerId& virtual_peer_id,RsTurtleGenericTunnelItem::Direction dir) +{ +#ifdef DEBUG_GXS_TUNNEL + std::cerr << "GxsTunnelService:: received new virtual peer " << virtual_peer_id << " for hash " << hash << ", dir=" << dir << std::endl; +#endif + RsGxsId own_gxs_id ; + + { + RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + + GxsTunnelDHInfo& dhinfo( _gxs_tunnel_virtual_peer_ids[virtual_peer_id] ) ; + dhinfo.gxs_id.clear() ; + + if(dhinfo.dh != NULL) + DH_free(dhinfo.dh) ; + + dhinfo.dh = NULL ; + dhinfo.direction = dir ; + dhinfo.hash = hash ; + dhinfo.status = RS_GXS_TUNNEL_DH_STATUS_UNINITIALIZED ; + + if(dir == RsTurtleGenericTunnelItem::DIRECTION_CLIENT) + { + // check that a tunnel is not already working for this hash. If so, give up. + + own_gxs_id = gxsIdFromHash(hash) ; + } + else // client side + { + RsGxsId to_gxs_id = gxsIdFromHash(hash) ; + std::map::const_iterator it = _gxs_tunnel_contacts.find(to_gxs_id) ; + + if(it == _gxs_tunnel_contacts.end()) + { + std::cerr << "(EE) no pre-registered peer for hash " << hash << " on client side. This is a bug." << std::endl; + return ; + } + + if(it->second.status == RS_GXS_TUNNEL_STATUS_CAN_TALK) + { + std::cerr << " virtual peer is for a distant chat session that is already openned and alive. Giving it up." << std::endl; + return ; + } + + own_gxs_id = it->second.own_gxs_id ; + } + +#ifdef DEBUG_GXS_TUNNEL + std::cerr << " Creating new virtual peer ID entry and empty DH session key." << std::endl; +#endif + + } + +#ifdef DEBUG_GXS_TUNNEL + std::cerr << " Adding virtual peer " << virtual_peer_id << " for chat hash " << hash << std::endl; +#endif + + // Start a new DH session for this tunnel + RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + + locked_restartDHSession(virtual_peer_id,own_gxs_id) ; +} + +void p3GxsTunnelService::locked_restartDHSession(const RsPeerId& virtual_peer_id,const RsGxsId& own_gxs_id) +{ +#ifdef DEBUG_GXS_TUNNEL + std::cerr << "Starting new DH session." << std::endl; +#endif + GxsTunnelDHInfo& dhinfo = _gxs_tunnel_virtual_peer_ids[virtual_peer_id] ; + + dhinfo.status = RS_GXS_TUNNEL_DH_STATUS_UNINITIALIZED ; + + if(!locked_initDHSessionKey(dhinfo.dh)) + { + std::cerr << " (EE) Cannot start DH session. Something went wrong." << std::endl; + return ; + } + dhinfo.status = RS_GXS_TUNNEL_DH_STATUS_HALF_KEY_DONE ; + + if(!locked_sendDHPublicKey(dhinfo.dh,own_gxs_id,virtual_peer_id)) + std::cerr << " (EE) Cannot send DH public key. Something went wrong." << std::endl; +} + +void p3GxsTunnelService::removeVirtualPeer(const TurtleFileHash& hash,const TurtleVirtualPeerId& virtual_peer_id) +{ + bool tunnel_dn = false ; + +#ifdef DEBUG_GXS_TUNNEL + std::cerr << "GxsTunnelService: Removing virtual peer " << virtual_peer_id << " for hash " << hash << std::endl; +#else + /* remove unused parameter warnings */ + (void) hash; +#endif + { + RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + + RsGxsId gxs_id ; + std::map::iterator it = _gxs_tunnel_virtual_peer_ids.find(virtual_peer_id) ; + + if(it == _gxs_tunnel_virtual_peer_ids.end()) + { + std::cerr << "(EE) Cannot remove virtual peer " << virtual_peer_id << ": not found in tunnel list!!" << std::endl; + return ; + } + + gxs_id = it->second.gxs_id ; + + if(it->second.dh != NULL) + DH_free(it->second.dh) ; + _gxs_tunnel_virtual_peer_ids.erase(it) ; + + std::map::iterator it2 = _gxs_tunnel_contacts.find(gxs_id) ; + + if(it2 == _gxs_tunnel_contacts.end()) + { + std::cerr << "(EE) Cannot find GXS id " << gxs_id << " in contact list. Weird." << std::endl; + return ; + } + if(it2->second.virtual_peer_id == virtual_peer_id) + { + it2->second.status = RS_GXS_TUNNEL_STATUS_TUNNEL_DN ; + it2->second.virtual_peer_id.clear() ; + tunnel_dn = true ; + } + } + + if(tunnel_dn) + { +#warning we should notify the client here + //RsServer::notify()->notifyChatStatus(ChatId(RsGxsId(virtual_peer_id)),"tunnel is down...") ; + //RsServer::notify()->notifyPeerStatusChanged(virtual_peer_id.toStdString(),RS_STATUS_OFFLINE) ; + } +} + +void p3GxsTunnelService::receiveTurtleData(RsTurtleGenericTunnelItem *gitem,const RsFileHash& hash, const RsPeerId& virtual_peer_id,RsTurtleGenericTunnelItem::Direction direction) +{ +#ifdef DEBUG_GXS_TUNNEL + std::cerr << "GxsTunnelService::receiveTurtleData(): Received turtle data. " << std::endl; + std::cerr << " hash = " << hash << std::endl; + std::cerr << " vpid = " << virtual_peer_id << std::endl; + std::cerr << " acting as = " << direction << std::endl; +#else + /* remove unused parameter warnings */ + (void) direction; +#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 ; + } + // 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 ; + } +#warning use flags here!! +#warning add a MAC to make sure the data is not forged + if(*((uint64_t*)item->data_bytes) != 0) // WTF?? we should use flags + { +#ifdef DEBUG_GXS_TUNNEL + std::cerr << " Item is encrypted." << std::endl; +#endif + + // if cannot decrypt, it means the key is wrong. We need to re-negociate a new key. + + handleEncryptedData((uint8_t*)item->data_bytes,item->data_size,hash,virtual_peer_id) ; + } + else + { +#ifdef DEBUG_GXS_TUNNEL + std::cerr << " Item is not encrypted." << std::endl; +#endif + + // Now try deserialise the decrypted data to make an RsItem out of it. + // +#warning needs proper passing of item to client + //RsItem *citem = RsChatSerialiser().deserialise(&((uint8_t*)item->data_bytes)[8],&item->data_size) ; + + if(citem == NULL) + { + std::cerr << "(EE) item could not be de-serialized. That is an error." << std::endl; + return ; + } + + // DH key items are sent even before we know who we speak to, so the virtual peer id is used in this + // case only. + + if(dynamic_cast(citem) != NULL) + { + citem->PeerId(virtual_peer_id) ; + handleIncomingItem(citem) ; + } + else + std::cerr << "(EE) Deserialiased item has unexpected type." << std::endl; + } +} + + +bool p3GxsTunnelService::handleEncryptedData(const uint8_t *data_bytes,uint32_t data_size,const TurtleFileHash& hash,const RsPeerId& virtual_peer_id) +{ +#ifdef DEBUG_GXS_TUNNEL + std::cerr << "p3GxsTunnelService::handleEncryptedDataItem()" << std::endl; + std::cerr << " size = " << data_size << std::endl; + std::cerr << " data = " << (void*)data_bytes << std::endl; + std::cerr << " IV = " << std::hex << *(uint64_t*)data_bytes << std::dec << std::endl; + std::cerr << " data = " << Bin2Hex((uint8_t*)data_bytes,data_size) ; + std::cerr << std::endl; +#endif + + RsItem *citem = NULL; + + { + RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + + uint32_t decrypted_size = RsAES::get_buffer_size(data_size-8); + uint8_t *decrypted_data = new uint8_t[decrypted_size]; + uint8_t aes_key[GXS_TUNNEL_AES_KEY_SIZE] ; + + std::map::iterator it = _gxs_tunnel_virtual_peer_ids.find(virtual_peer_id) ; + + if(it == _gxs_tunnel_virtual_peer_ids.end()) + { + std::cerr << "(EE) item is not coming out of a registered tunnel. Weird. hash=" << hash << ", peer id = " << virtual_peer_id << std::endl; + return true ; + } + + RsGxsId gxs_id = it->second.gxs_id ; + std::map::iterator it2 = _gxs_tunnel_contacts.find(gxs_id) ; + + if(it2 == _gxs_tunnel_contacts.end()) + { + std::cerr << "(EE) no GXS id data for ID=" << gxs_id << ". This is a bug." << std::endl; + return true ; + } + memcpy(aes_key,it2->second.aes_key,GXS_TUNNEL_AES_KEY_SIZE) ; + +#ifdef DEBUG_GXS_TUNNEL + std::cerr << " Using IV: " << std::hex << *(uint64_t*)data_bytes << std::dec << std::endl; + std::cerr << " Decrypted buffer size: " << decrypted_size << std::endl; + std::cerr << " key : " << Bin2Hex(aes_key,16) << ; std::cerr << std::endl; + std::cerr << " data : " << Bin2Hex((uint8_t*)data_bytes,data_size) << ; std::cerr << std::endl; +#endif + + if(!RsAES::aes_decrypt_8_16((uint8_t*)data_bytes+8,data_size-8,aes_key,(uint8_t*)data_bytes,decrypted_data,decrypted_size)) + { + std::cerr << "(EE) packet decryption failed." << std::endl; + std::cerr << "(EE) resetting new DH session." << std::endl; + + delete[] decrypted_data ; + + locked_restartDHSession(virtual_peer_id,it2->second.own_gxs_id) ; + + return false ; + } + it2->second.status = RS_GXS_TUNNEL_STATUS_CAN_TALK ; + it2->second.last_contact = time(NULL) ; + +#ifdef DEBUG_GXS_TUNNEL + std::cerr << "(II) Decrypted data: size=" << decrypted_size << std::endl; +#endif + + // Now try deserialise the decrypted data to make an RsItem out of it. + // +#warning pass on the serialised data directly to client (see what GRouter does) + //citem = RsChatSerialiser().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 true; + } + + // DH key items are sent even before we know who we speak to, so the virtual peer id is used in this + // case only. + + citem->PeerId(RsPeerId(gxs_id)) ; + } + +#ifdef DEBUG_GXS_TUNNEL + std::cerr << "(II) Setting peer id to " << citem->PeerId() << std::endl; +#endif + handleIncomingItem(citem) ; // Treats the item, and deletes it + + return true ; +} + +void p3GxsTunnelService::handleRecvDHPublicKey(RsGxsTunnelDHPublicKeyItem *item) +{ + if (!item) + { + std::cerr << "p3GxsTunnelService: Received null DH public key item. This should not happen." << std::endl; + return; + } + +#ifdef DEBUG_GXS_TUNNEL + std::cerr << "GxsTunnelService: Received DH public key." << std::endl; + item->print(std::cerr, 0) ; +#endif + + // Look for the current state of the key agreement. + + TurtleVirtualPeerId vpid = item->PeerId() ; + + RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + + std::map::iterator it = _gxs_tunnel_virtual_peer_ids.find(vpid) ; + + if(it == _gxs_tunnel_virtual_peer_ids.end()) + { + std::cerr << " (EE) Cannot find hash in gxs_tunnel peer list!!" << std::endl; + return ; + } + + // Now check the signature of the DH public key item. + +#ifdef DEBUG_GXS_TUNNEL + std::cerr << " Checking signature. " << std::endl; +#endif + + uint32_t pubkey_size = BN_num_bytes(item->public_key) ; + unsigned char *data = (unsigned char *)malloc(pubkey_size) ; + BN_bn2bin(item->public_key, data) ; + + RsTlvSecurityKey signature_key ; + + // We need to get the key of the sender, but if the key is not cached, we + // need to get it first. So we let the system work for 2-3 seconds before + // giving up. Normally this would only cause a delay for uncached keys, + // which is rare. To force the system to cache the key, we first call for + // getIdDetails(). + // + RsIdentityDetails details ; + RsGxsId senders_id( item->signature.keyId ) ; + + for(int i=0;i<6;++i) + if(!mGixs->getKey(senders_id,signature_key) || signature_key.keyData.bin_data == NULL) + { +#ifdef DEBUG_GXS_TUNNEL + std::cerr << " Cannot get key. Waiting for caching. try " << i << "/6" << std::endl; +#endif + usleep(500 * 1000) ; // sleep for 500 msec. + } + else + break ; + + if(signature_key.keyData.bin_data == NULL) + { + std::cerr << " (EE) Key unknown for checking signature from " << senders_id << ", can't verify signature. Using key provided in DH packet (without adding to the keyring)." << std::endl; + + // check GXS key for defects. + + if(!GxsSecurity::checkPublicKey(item->gxs_key)) + { + std::cerr << "(SS) Security error in distant chat DH handshake: supplied key " << item->gxs_key.keyId << " is inconsistent. Refusing chat!" << std::endl; + return ; + } + if(item->gxs_key.keyId != item->signature.keyId) + { + std::cerr << "(SS) Security error in distant chat DH handshake: supplied key " << item->gxs_key.keyId << " is not the same than the item's signature key " << item->signature.keyId << ". Refusing chat!" << std::endl; + return ; + } + + signature_key = item->gxs_key ; + } + + if(!GxsSecurity::validateSignature((char*)data,pubkey_size,signature_key,item->signature)) + { + std::cerr << "(SS) Signature was verified and it doesn't check! This is a security issue!" << std::endl; + return ; + } + mGixs->timeStampKey(item->signature.keyId) ; + +#ifdef DEBUG_GXS_TUNNEL + std::cerr << " Signature checks! Sender's ID = " << senders_id << std::endl; + std::cerr << " Computing AES key" << std::endl; +#endif + + if(it->second.dh == NULL) + { + std::cerr << " (EE) no DH information for that peer. This is an error." << std::endl; + return ; + } + if(it->second.status == RS_GXS_TUNNEL_DH_STATUS_KEY_AVAILABLE) + { +#ifdef DEBUG_GXS_TUNNEL + std::cerr << " DH Session already set for this tunnel. Re-initing a new session!" << std::endl; +#endif + + locked_restartDHSession(vpid,_gxs_tunnel_contacts[senders_id].own_gxs_id) ; + } + + // gets current key params. By default, should contain all null pointers. + // + it->second.gxs_id = senders_id ; + + // Looks for the DH params. If not there yet, create them. + // + int size = DH_size(it->second.dh) ; + unsigned char *key_buff = new unsigned char[size] ; + + if(size != DH_compute_key(key_buff,item->public_key,it->second.dh)) + { + std::cerr << " (EE) DH computation failed. Probably a bug. Error code=" << ERR_get_error() << std::endl; + return ; + } + it->second.status = RS_GXS_TUNNEL_DH_STATUS_KEY_AVAILABLE ; + +#ifdef DEBUG_GXS_TUNNEL + std::cerr << " DH key computation successed. New key in place." << std::endl; +#endif + GxsTunnelPeerInfo& pinfo(_gxs_tunnel_contacts[senders_id]) ; + + // Now hash the key buffer into a 16 bytes key. + + assert(GXS_TUNNEL_AES_KEY_SIZE <= Sha1CheckSum::SIZE_IN_BYTES) ; + memcpy(pinfo.aes_key, RsDirUtil::sha1sum(key_buff,size).toByteArray(),GXS_TUNNEL_AES_KEY_SIZE) ; + delete[] key_buff ; + + pinfo.last_contact = time(NULL) ; + pinfo.last_keep_alive_sent = time(NULL) ; + pinfo.status = RS_GXS_TUNNEL_STATUS_CAN_TALK ; + pinfo.virtual_peer_id = vpid ; + pinfo.direction = it->second.direction ; + + if(pinfo.direction == RsTurtleGenericTunnelItem::DIRECTION_CLIENT) + pinfo.own_gxs_id = gxsIdFromHash(it->second.hash) ; + +#ifdef DEBUG_GXS_TUNNEL + std::cerr << " DH key computed. Tunnel is now secured!" << std::endl; + std::cerr << " Key computed: " << Bin2Hex(pinfo.aes_key,16) << std::cerr << std::endl; + std::cerr << " Sending a ACK packet." << std::endl; +#endif + + // then we send an ACK packet to notify that the tunnel works. That's useful + // because it makes the peer at the other end of the tunnel know that all + // intermediate peer in the tunnel are able to transmit the data. + // However, it is not possible here to call sendTurtleData(), without dead-locking + // the turtle router, so we store the item is a list of items to be sent. + + RsGxsTunnelStatusItem *cs = new RsGxsTunnelStatusItem ; + + cs->flags = RS_GXS_TUNNEL_FLAG_ACK_DISTANT_CONNECTION; + cs->PeerId(RsPeerId(senders_id)); + + pendingGxsTunnelItems.push_back(cs) ; + +#warning should notify client here + //RsServer::notify()->notifyListChange(NOTIFY_LIST_PRIVATE_INCOMING_CHAT, NOTIFY_TYPE_ADD); +} + +bool GxsTunnelService::locked_sendDHPublicKey(const DH *dh,const RsGxsId& own_gxs_id,const RsPeerId& virtual_peer_id) +{ + if(dh == NULL) + { + std::cerr << " (EE) DH struct is not initialised! Error." << std::endl; + return false ; + } + + RsGxsTunnelDHPublicKeyItem *dhitem = new RsGxsTunnelDHPublicKeyItem ; + dhitem->public_key = BN_dup(dh->pub_key) ; + + // we should also sign the data and check the signature on the other end. + // + RsTlvKeySignature signature ; + RsTlvSecurityKey signature_key ; + RsTlvSecurityKey signature_key_public ; + + uint32_t error_status ; + + uint32_t size = BN_num_bytes(dhitem->public_key) ; + unsigned char *data = (unsigned char *)malloc(size) ; + BN_bn2bin(dhitem->public_key, data) ; + + if(!mGixs->signData((unsigned char*)data,size,own_gxs_id,signature,error_status)) + { + switch(error_status) + { + case RsGixs::RS_GIXS_ERROR_KEY_NOT_AVAILABLE: std::cerr << "(EE) Key is not available. Cannot sign." << std::endl; + break ; + default: std::cerr << "(EE) Unknown error when signing" << std::endl; + break ; + } + free(data) ; + delete(dhitem); + return false; + } + free(data) ; + + if(!mGixs->getKey(own_gxs_id,signature_key_public)) + { + std::cerr << " (EE) Could not retrieve own public key for ID = " << own_gxs_id << ". Giging up sending DH session params." << std::endl; + return false ; + } + + + assert(!(signature_key_public.keyFlags & RSTLV_KEY_TYPE_FULL)) ; + + dhitem->signature = signature ; + dhitem->gxs_key = signature_key_public ; + dhitem->PeerId(RsPeerId(virtual_peer_id)) ; // special case for DH items + +#ifdef DEBUG_GXS_TUNNEL + std::cerr << " Pushing DH session key item to pending distant messages..." << std::endl; + dhitem->print(std::cerr, 2) ; + std::cerr << std::endl; +#endif + pendingGxsTunnelItems.push_back(dhitem) ; // sent off-mutex to avoid deadlocking. + + return true ; +} + +bool GxsTunnelService::locked_initDHSessionKey(DH *& dh) +{ + // We use our own DH group prime. This has been generated with command-line openssl and checked. + + static const std::string dh_prime_2048_hex = "B3B86A844550486C7EA459FA468D3A8EFD71139593FE1C658BBEFA9B2FC0AD2628242C2CDC2F91F5B220ED29AAC271192A7374DFA28CDDCA70252F342D0821273940344A7A6A3CB70C7897A39864309F6CAC5C7EA18020EF882693CA2C12BB211B7BA8367D5A7C7252A5B5E840C9E8F081469EBA0B98BCC3F593A4D9C4D5DF539362084F1B9581316C1F80FDAD452FD56DBC6B8ED0775F596F7BB22A3FE2B4753764221528D33DB4140DE58083DB660E3E105123FC963BFF108AC3A268B7380FFA72005A1515C371287C5706FFA6062C9AC73A9B1A6AC842C2764CDACFC85556607E86611FDF486C222E4896CDF6908F239E177ACC641FCBFF72A758D1C10CBB" ; + + if(dh != NULL) + { + DH_free(dh) ; + dh = NULL ; + } + + dh = DH_new() ; + + if(!dh) + { + std::cerr << " (EE) DH_new() failed." << std::endl; + return false ; + } + + BN_hex2bn(&dh->p,dh_prime_2048_hex.c_str()) ; + BN_hex2bn(&dh->g,"5") ; + + int codes = 0 ; + + if(!DH_check(dh, &codes) || codes != 0) + { + std::cerr << " (EE) DH check failed!" << std::endl; + return false ; + } + + if(!DH_generate_key(dh)) + { + std::cerr << " (EE) DH generate_key() failed! Error code = " << ERR_get_error() << std::endl; + return false ; + } +#ifdef DEBUG_GXS_TUNNEL + std::cerr << " (II) DH Session key inited." << std::endl; +#endif + return true ; +} + +void p3GxsTunnelService::sendTurtleData(RsChatItem *item) +{ +#ifdef DEBUG_GXS_TUNNEL + std::cerr << "GxsTunnelService::sendTurtleData(): try sending item " << (void*)item << " to peer " << item->PeerId() << std::endl; +#endif + + if(dynamic_cast(item) != NULL) + { + // make a TurtleGenericData item out of it, and send it in clear. + // + RsTurtleGenericDataItem *gitem = new RsTurtleGenericDataItem ; + + uint32_t rssize = item->serial_size() ; + + gitem->data_size = rssize + 8 ; + gitem->data_bytes = malloc(rssize+8) ; + + memset(gitem->data_bytes,0,8) ; + + if(!item->serialise(&((uint8_t*)gitem->data_bytes)[8],rssize)) + { + std::cerr << "(EE) Could not serialise item!!!" << std::endl; + delete gitem ; + delete item ; + return ; + } + +#ifdef DEBUG_GXS_TUNNEL + std::cerr << " GxsTunnelService::sendTurtleData(): Sending clear data to virtual peer: " << item->PeerId() << std::endl; + std::cerr << " gitem->data_size = " << gitem->data_size << std::endl; + std::cerr << " data = " << Bin2Hex(gitem->data_bytes,gitem->data_size) ; + std::cerr << std::endl; +#endif + mTurtle->sendTurtleData(item->PeerId(),gitem) ; + } + else + { + uint32_t rssize = item->serial_size(); + uint8_t *buff = (uint8_t*)malloc(rssize) ; + + if(!item->serialise(buff,rssize)) + { + std::cerr << "(EE) GxsTunnelService::sendTurtleData(): Could not serialise item!" << std::endl; + free(buff) ; + delete item ; + return ; + } + + sendEncryptedTurtleData(buff,rssize,RsGxsId(item->PeerId())) ; + + free(buff) ; + } + delete item ; +} + +void p3GxsTunnelService::sendEncryptedTurtleData(const uint8_t *buff,uint32_t rssize,const RsGxsId& gxs_id) +{ + uint8_t aes_key[GXS_TUNNEL_AES_KEY_SIZE] ; + uint64_t IV = 0; + +#ifdef DEBUG_GXS_TUNNEL + std::cerr << "Sending encrypted data to virtual gxs id " << gxs_id << std::endl; +#endif + RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + + std::map::iterator it = _gxs_tunnel_contacts.find(gxs_id) ; + + if(it == _gxs_tunnel_contacts.end()) + { + std::cerr << "(EE) Cannot find contact key info for ID " << gxs_id << ". Cannot send message!" << std::endl; + return ; + } + if(it->second.status != RS_GXS_TUNNEL_STATUS_CAN_TALK) + { + std::cerr << "(EE) Cannot talk to " << gxs_id << ". Tunnel status is: " << it->second.status << std::endl; + return ; + } + + memcpy(aes_key,it->second.aes_key,GXS_TUNNEL_AES_KEY_SIZE) ; + RsPeerId virtual_peer_id = it->second.virtual_peer_id ; + + while(IV == 0) IV = RSRandom::random_u64() ; // make a random 8 bytes IV, that is not 0 + +#ifdef DEBUG_GXS_TUNNEL + std::cerr << "GxsTunnelService::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); + +#ifdef DEBUG_GXS_TUNNEL + std::cerr << " Using IV: " << std::hex << IV << std::dec << std::endl; + std::cerr << " Using Key: " << Bin2Hex(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 ; + return ; + } + + // 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(& (((uint8_t*)gitem->data_bytes)[8]),encrypted_data,encrypted_size) ; + + delete[] encrypted_data ; + +#ifdef DEBUG_GXS_TUNNEL + std::cerr << "GxsTunnelService::sendTurtleData(): Sending encrypted data to virtual peer: " << virtual_peer_id << std::endl; + std::cerr << " gitem->data_size = " << gitem->data_size << std::endl; + std::cerr << " data = " << Bin2Hex(gitem->data_bytes,gitem->data_size) ; + std::cerr << std::endl; +#endif + + mTurtle->sendTurtleData(virtual_peer_id,gitem) ; +} + +bool p3GxsTunnelService::initiateGxsTunnelConnexion(const RsGxsId& to_gxs_id,const RsGxsId& from_gxs_id,uint32_t& error_code) +{ + // should be a parameter. + + std::list lst ; + mGixs->getOwnIds(lst) ; + + bool found = false ; + for(std::list::const_iterator it = lst.begin();it!=lst.end();++it) + if(*it == from_gxs_id) + { + found=true; + break ; + } + + if(!found) + { + std::cerr << " (EE) Cannot start distant chat, since GXS id " << from_gxs_id << " is not available." << std::endl; + return false ; + } + RsGxsId own_gxs_id = from_gxs_id ; + + startClientGxsTunnelConnection(to_gxs_id,own_gxs_id) ; + + error_code = RS_GXS_TUNNEL_ERROR_NO_ERROR ; + + return true ; +} + +void p3GxsTunnelService::startClientGxsTunnelConnection(const RsGxsId& to_gxs_id,const RsGxsId& from_gxs_id) +{ + { + RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + + if(_gxs_tunnel_contacts.find(to_gxs_id) != _gxs_tunnel_contacts.end()) + { + std::cerr << "GxsTunnelService:: asking distant chat connexion to a peer who's already in a chat. Ignoring." << std::endl; + return ; + } + } + GxsTunnelPeerInfo info ; + + time_t now = time(NULL) ; + + info.last_contact = now ; + info.last_keep_alive_sent = now ; + info.status = RS_GXS_TUNNEL_STATUS_TUNNEL_DN ; + info.own_gxs_id = from_gxs_id ; + info.direction = RsTurtleGenericTunnelItem::DIRECTION_SERVER ; + info.virtual_peer_id.clear(); + + memset(info.aes_key,0,GXS_TUNNEL_AES_KEY_SIZE) ; + + { + RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + _gxs_tunnel_contacts[to_gxs_id] = info ; + } + + // Now ask the turtle router to manage a tunnel for that hash. + + RsFileHash hash = hashFromGxsId(to_gxs_id) ; +#ifdef DEBUG_GXS_TUNNEL + std::cerr << "Starting distant chat to " << to_gxs_id << ", hash = " << hash << ", from " << from_gxs_id << std::endl; + std::cerr << "Asking turtle router to monitor tunnels for hash " << hash << std::endl; +#endif + + mTurtle->monitorTunnels(hash,this,false) ; + +#warning check that this code should go. +#ifdef TO_BE_REMOVED + // spawn a status item so as to open the chat window. + RsChatMsgItem *item = new RsChatMsgItem; + item->message = "[Starting distant chat. Please wait for secure tunnel to be established]" ; + item->chatFlags = RS_CHAT_FLAG_PRIVATE ; + item->PeerId(RsPeerId(to_gxs_id)) ; + handleRecvChatMsgItem(item) ; +#endif +} + +TurtleFileHash p3GxsTunnelService::hashFromGxsId(const RsGxsId& destination) +{ + // This is in prevision for the "secured GXS tunnel" service, which will need a service ID to register, + // just like GRouter does. + + static const uint32_t client = RS_SERVICE_TYPE_GXS_TUNNEL ; + + assert( destination.SIZE_IN_BYTES == 16) ; + assert(Sha1CheckSum::SIZE_IN_BYTES == 20) ; + + uint8_t bytes[20] ; + memcpy(bytes,destination.toByteArray(),16) ; + bytes[16] = 0 ; + bytes[17] = 0 ; + bytes[18] = (client >> 8) & 0xff ; + bytes[19] = client & 0xff ; + + // We could rehash this, with a secret key to get a HMAC. That would allow to publish secret distant chat + // passphrases. I'll do this later if needed. + + return Sha1CheckSum(bytes) ; +} + +RsGxsId p3GxsTunnelService::gxsIdFromHash(const TurtleFileHash& sum) +{ + assert( RsGxsId::SIZE_IN_BYTES == 16) ; + assert(Sha1CheckSum::SIZE_IN_BYTES == 20) ; + + uint32_t client_id = sum.toByteArray()[19] + (sum.toByteArray()[18] << 8) ; + + if(client_id != RS_SERVICE_TYPE_GXS_TUNNEL) + std::cerr << "WARNING: GxsTunnelService::gxsIdFromHash(). Hash is not a distant file hash. This should not happen." << std::endl; + + return RsGxsId(sum.toByteArray());// takes the first 16 bytes +} + +bool p3GxsTunnelService::getGxsTunnelStatus(const RsGxsId& gxs_id,uint32_t& status, RsGxsId *from_gxs_id) +{ + RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + + std::map::const_iterator it = _gxs_tunnel_contacts.find(gxs_id) ; + + if(it != _gxs_tunnel_contacts.end()) + { + status = it->second.status ; + + if(from_gxs_id != NULL) + *from_gxs_id = it->second.own_gxs_id ; + + return true ; + } + + status = RS_GXS_TUNNEL_STATUS_UNKNOWN ; + + return false ; +} + +bool p3GxsTunnelService::closeGxsTunnelConnexion(const RsGxsId& gxs_id) +{ + // two cases: + // - client needs to stop asking for tunnels => remove the hash from the list of tunnelled files + // - server needs to only close the window and let the tunnel die. But the window should only open + // if a message arrives. + + { + RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + std::map::const_iterator it = _gxs_tunnel_contacts.find(gxs_id) ; + + if(it == _gxs_tunnel_contacts.end()) + { + std::cerr << "(EE) Cannot close distant tunnel connection. No connection openned for gxs id " << gxs_id << std::endl; + + // We don't know if we are server or client side, but mTurtle will not complain if the hash doesn't exist. + + mTurtle->stopMonitoringTunnels( hashFromGxsId(gxs_id) ); + + return false ; + } + if(it->second.direction == RsTurtleGenericTunnelItem::DIRECTION_CLIENT) // nothing more to do for server side. + return true ; + } + + // send a status item saying that we're closing the connection +#ifdef DEBUG_GXS_TUNNEL + std::cerr << " Sending a ACK to close the tunnel since we're managing it. Peer id=." << gxs_id << std::endl; +#endif + + RsGxsTunnelStatusItem *cs = new RsGxsTunnelStatusItem ; + + cs->flags = RS_CHAT_FLAG_CLOSING_DISTANT_CONNECTION; + cs->PeerId(RsPeerId(gxs_id)); + + sendTurtleData(cs) ; // that needs to be done off-mutex and before we close the tunnel. + +#ifdef DEBUG_GXS_TUNNEL + std::cerr << " This is client side. Stopping tunnel manageement for gxs_id " << gxs_id << std::endl; +#endif + mTurtle->stopMonitoringTunnels( hashFromGxsId(gxs_id) ); + { + RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + std::map::iterator it = _gxs_tunnel_contacts.find(gxs_id) ; + + if(it == _gxs_tunnel_contacts.end()) // server side. Nothing to do. + { + std::cerr << "(EE) Cannot close chat associated to GXS id " << gxs_id << ": not found." << std::endl; + return false ; + } + + _gxs_tunnel_contacts.erase(it) ; + + // GxsTunnelService::removeVirtualPeerId() will be called by the turtle service. + } + return true ; +} + +void p3GxsTunnelService::markGxsTunnelAsClosed(const RsGxsId& gxs_id) +{ + RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + + std::map::iterator it = _gxs_tunnel_contacts.find(gxs_id) ; + + if(it == _gxs_tunnel_contacts.end()) + { + std::cerr << "(EE) Cannot mark distant chat connection as closed. No connection openned for gxs id " << gxs_id << ". Unexpected situation." << std::endl; + return ; + } + + if(it->second.direction == RsTurtleGenericDataItem::DIRECTION_CLIENT) + { +#ifdef DEBUG_GXS_TUNNEL + std::cerr << " This is server side. Marking distant chat as remotely closed for GXS id " << gxs_id << std::endl; +#endif + it->second.status = RS_GXS_TUNNEL_STATUS_REMOTELY_CLOSED ; + } +} + diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.h b/libretroshare/src/gxstunnel/p3gxstunnel.h new file mode 100644 index 000000000..c08c57690 --- /dev/null +++ b/libretroshare/src/gxstunnel/p3gxstunnel.h @@ -0,0 +1,138 @@ +/* + * libretroshare/src/chat: distantchat.h + * + * Services for RetroShare. + * + * Copyright 2014 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". + * + */ + +#pragma once + +#include +#include + +class RsGixs ; + +static const uint32_t GXS_TUNNEL_AES_KEY_SIZE = 16 ; + +class p3GxsTunnelService: public RsGxsTunnelService, public RsTurtleClientService +{ +public: + p3GxsTunnelService(RsGixs *pids) + : mGixs(pids), mGxsTunnelMtx("GXS tunnel") + { + mTurtle = NULL ; + } + + void flush() ; + + virtual void connectToTurtleRouter(p3turtle *) ; + + // Creates the invite if the public key of the distant peer is available. + // Om success, stores the invite in the map above, so that we can respond to tunnel requests. + // + bool initiateTunnelConnexion(const RsGxsId& to_gxs_id,const RsGxsId &from_gxs_id, uint32_t &error_code) ; + bool closeTunnelConnexion(const RsGxsId& pid) ; + virtual bool getTunnelStatus(const RsGxsId &gxs_id,uint32_t &status, RsGxsId *from_gxs_id=NULL) ; + + virtual void handleIncomingItem(RsItem *) ; + +private: + class GxsTunnelPeerInfo + { + public: + GxsTunnelPeerInfo() : last_contact(0), last_keep_alive_sent(0), status(0), direction(0) + { + memset(aes_key, 0, GXS_TUNNEL_AES_KEY_SIZE); + } + + time_t last_contact ; // used to keep track of working connexion + time_t last_keep_alive_sent ; // last time we sent a keep alive packet. + + unsigned char aes_key[GXS_TUNNEL_AES_KEY_SIZE] ; + + uint32_t status ; // info: do we have a tunnel ? + RsPeerId virtual_peer_id; // given by the turtle router. Identifies the tunnel. + RsGxsId own_gxs_id ; // gxs id we're using to talk. + RsTurtleGenericTunnelItem::Direction direction ; // specifiec wether we are client(managing the tunnel) or server. + }; + + class GxsTunnelDHInfo + { + public: + GxsTunnelDHInfo() : dh(0), direction(0), status(0) {} + + DH *dh ; + RsGxsId gxs_id ; + RsTurtleGenericTunnelItem::Direction direction ; + uint32_t status ; + TurtleFileHash hash ; + }; + + // This maps contains the current peers to talk to with distant chat. + // + std::map _gxs_tunnel_contacts ; // current peers we can talk to + std::map _gxs_tunnel_virtual_peer_ids ; // current virtual peers. Used to figure out tunnels, etc. + + // List of items to be sent asap. Used to store items that we cannot pass directly to + // sendTurtleData(), because of Mutex protection. + + std::list pendingDistantChatItems ; + + // Overloaded from RsTurtleClientService + + virtual bool handleTunnelRequest(const RsFileHash &hash,const RsPeerId& peer_id) ; + virtual void receiveTurtleData(RsTurtleGenericTunnelItem *item,const RsFileHash& hash,const RsPeerId& virtual_peer_id,RsTurtleGenericTunnelItem::Direction direction) ; + void addVirtualPeer(const TurtleFileHash&, const TurtleVirtualPeerId&,RsTurtleGenericTunnelItem::Direction dir) ; + void removeVirtualPeer(const TurtleFileHash&, const TurtleVirtualPeerId&) ; + + // session handling handles + + void markGxsTunnelAsClosed(const RsGxsId &gxs_id) ; + void startClientGxsTunnelConnection(const RsGxsId &to_gxs_id,const RsGxsId& from_gxs_id) ; + void locked_restartDHSession(const RsPeerId &virtual_peer_id, const RsGxsId &own_gxs_id) ; + + // utility functions + + static TurtleFileHash hashFromGxsId(const RsGxsId& destination) ; + static RsGxsId gxsIdFromHash(const TurtleFileHash& sum) ; + + // Cryptography management + + void handleRecvDHPublicKey(RsGxsTunnelDHPublicKeyItem *item) ; + bool locked_sendDHPublicKey(const DH *dh, const RsGxsId& own_gxs_id, const RsPeerId& virtual_peer_id) ; + bool locked_initDHSessionKey(DH *&dh); + + GxsTunnelPeerId virtualPeerIdFromHash(const TurtleFileHash& hash) ; // ... and to a hash for p3turtle + + // Comunication with Turtle service + + void sendTurtleData(RsGxsTunnelItem *) ; + void sendEncryptedTurtleData(const uint8_t *buff,uint32_t rssize,const RsGxsId &gxs_id) ; + bool handleEncryptedData(const uint8_t *data_bytes,uint32_t data_size,const TurtleFileHash& hash,const RsPeerId& virtual_peer_id) ; + + static TurtleFileHash hashFromVirtualPeerId(const DistantChatPeerId& peerId) ; // converts IDs so that we can talk to RsPeerId from outside + + // local data + + p3turtle *mTurtle ; + RsGixs *mGixs ; + RsMutex mGxsTunnelMtx ; +}; diff --git a/libretroshare/src/gxstunnel/rsgxstunnelitems.cc b/libretroshare/src/gxstunnel/rsgxstunnelitems.cc new file mode 100644 index 000000000..e44102bc4 --- /dev/null +++ b/libretroshare/src/gxstunnel/rsgxstunnelitems.cc @@ -0,0 +1,1362 @@ + +/* + * libretroshare/src/serialiser: rsbaseitems.cc + * + * RetroShare Serialiser. + * + * Copyright 2007-2008 by Robert Fernie. + * + * 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 +#include +#include "serialiser/rsbaseserial.h" +#include "serialiser/rstlvbase.h" + +#include "chat/rschatitems.h" + +//#define CHAT_DEBUG 1 + +std::ostream& RsChatMsgItem::print(std::ostream &out, uint16_t indent) +{ + printRsItemBase(out, "RsChatMsgItem", indent); + uint16_t int_Indent = indent + 2; + printIndent(out, int_Indent); + out << "QblogMs " << chatFlags << std::endl; + + printIndent(out, int_Indent); + out << "sendTime: " << sendTime << " (" << time(NULL)-sendTime << " secs ago)" << std::endl; + + printIndent(out, int_Indent); + + std::string cnv_message(message.begin(), message.end()); + out << "msg: " << cnv_message << std::endl; + + printRsItemEnd(out, "RsChatMsgItem", indent); + return out; +} +std::ostream& RsChatDHPublicKeyItem::print(std::ostream &out, uint16_t indent) +{ + printRsItemBase(out, "RsChatDHPublicKeyItem", indent); + uint16_t int_Indent = indent + 2; + + printIndent(out, int_Indent); + out << " Signature Key ID: " << signature.keyId << std::endl ; + out << " Public Key ID: " << gxs_key.keyId << std::endl ; + + printRsItemEnd(out, "RsChatMsgItem", indent); + return out; +} + +std::ostream& RsChatLobbyListItem::print(std::ostream &out, uint16_t indent) +{ + printRsItemBase(out, "RsChatLobbyListItem", indent); + + for(uint32_t i=0;iPeerId()); + configPeerId = ci->PeerId(); + chatFlags = ci->chatFlags; + configFlags = confFlags; + sendTime = ci->sendTime; + message = ci->message; + recvTime = ci->recvTime; +} + +/* get data from RsPrivateChatMsgConfigItem to RsChatMsgItem */ +void RsPrivateChatMsgConfigItem::get(RsChatMsgItem *ci) +{ + ci->PeerId(configPeerId); + ci->chatFlags = chatFlags; + //configFlags not used + ci->sendTime = sendTime; + ci->message = message; + ci->recvTime = recvTime; +} + +RsChatStatusItem::RsChatStatusItem(void *data,uint32_t /*size*/) + : RsChatItem(RS_PKT_SUBTYPE_CHAT_STATUS) +{ + uint32_t offset = 8; // skip the header + uint32_t rssize = getRsItemSize(data); + bool ok = true ; + +#ifdef CHAT_DEBUG + std::cerr << "Building new chat status item." << std::endl ; +#endif + /* get mandatory parts first */ + ok &= getRawUInt32(data, rssize, &offset, &flags); + ok &= GetTlvString(data, rssize, &offset,TLV_TYPE_STR_MSG, status_string); + + if (offset != rssize) + std::cerr << "Size error while deserializing." << std::endl ; + if (!ok) + std::cerr << "Unknown error while deserializing." << std::endl ; +} + +RsChatAvatarItem::RsChatAvatarItem(void *data,uint32_t /*size*/) + : RsChatItem(RS_PKT_SUBTYPE_CHAT_AVATAR) +{ + uint32_t offset = 8; // skip the header + uint32_t rssize = getRsItemSize(data); + bool ok = true ; + +#ifdef CHAT_DEBUG + std::cerr << "Building new chat status item." << std::endl ; +#endif + /* get mandatory parts first */ + ok &= getRawUInt32(data, rssize, &offset,&image_size); + + // ensure invalid image length does not overflow data + if( (offset + image_size) <= rssize){ + image_data = new unsigned char[image_size] ; + memcpy(image_data,(void*)((unsigned char*)data+offset),image_size) ; + offset += image_size ; + }else{ + ok = false; + std::cerr << "offset+image_size exceeds rssize" << std::endl; + } + + if (offset != rssize) + std::cerr << "Size error while deserializing." << std::endl ; + if (!ok) + std::cerr << "Unknown error while deserializing." << std::endl ; +} + + diff --git a/libretroshare/src/gxstunnel/rsgxstunnelitems.h b/libretroshare/src/gxstunnel/rsgxstunnelitems.h new file mode 100644 index 000000000..34c960d95 --- /dev/null +++ b/libretroshare/src/gxstunnel/rsgxstunnelitems.h @@ -0,0 +1,430 @@ +/* + * libretroshare/src/serialiser: rschatitems.h + * + * RetroShare Serialiser. + * + * Copyright 2007-2008 by Robert Fernie. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License Version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems to "retroshare@lunamutt.com". + * + */ + +#pragma once + +#include "openssl/bn.h" +#include "retroshare/rstypes.h" +#include "serialiser/rstlvkeys.h" +#include "serialiser/rsserviceids.h" +#include "serialiser/rsserial.h" + +#include "serialiser/rstlvidset.h" +#include "serialiser/rstlvfileitem.h" + +/* chat Flags */ +const uint32_t RS_CHAT_FLAG_PRIVATE = 0x0001; +const uint32_t RS_CHAT_FLAG_REQUESTS_AVATAR = 0x0002; +const uint32_t RS_CHAT_FLAG_CONTAINS_AVATAR = 0x0004; +const uint32_t RS_CHAT_FLAG_AVATAR_AVAILABLE = 0x0008; +const uint32_t RS_CHAT_FLAG_CUSTOM_STATE = 0x0010; // used for transmitting peer status string +const uint32_t RS_CHAT_FLAG_PUBLIC = 0x0020; +const uint32_t RS_CHAT_FLAG_REQUEST_CUSTOM_STATE = 0x0040; +const uint32_t RS_CHAT_FLAG_CUSTOM_STATE_AVAILABLE = 0x0080; +const uint32_t RS_CHAT_FLAG_PARTIAL_MESSAGE = 0x0100; +const uint32_t RS_CHAT_FLAG_LOBBY = 0x0200; +const uint32_t RS_CHAT_FLAG_CLOSING_DISTANT_CONNECTION = 0x0400; +const uint32_t RS_CHAT_FLAG_ACK_DISTANT_CONNECTION = 0x0800; +const uint32_t RS_CHAT_FLAG_KEEP_ALIVE = 0x1000; + +const uint32_t RS_CHATMSG_CONFIGFLAG_INCOMING = 0x0001; + +const uint8_t RS_PKT_SUBTYPE_CHAT_AVATAR = 0x03 ; +const uint8_t RS_PKT_SUBTYPE_CHAT_STATUS = 0x04 ; +const uint8_t RS_PKT_SUBTYPE_PRIVATECHATMSG_CONFIG = 0x05 ; +const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_MSG_DEPRECATED = 0x06 ; // don't use ! Deprecated +const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_INVITE_DEPREC = 0x07 ; // don't use ! Deprecated +const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_ACCEPT = 0x08 ; +const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_CHALLENGE = 0x09 ; +const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_UNSUBSCRIBE = 0x0A ; +const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_EVENT_DEPREC = 0x0B ; // don't use ! Deprecated +const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_MSG = 0x0C ; // will be deprecated when only signed messages are accepted (02/2015) +const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_LIST_REQUEST = 0x0D ; +const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_LIST_deprecated = 0x0E ; // to be removed +const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_INVITE_deprecated = 0x0F ; // to be removed +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_deprecated3 = 0x12 ; +const uint8_t RS_PKT_SUBTYPE_DISTANT_INVITE_CONFIG = 0x13 ; +const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_CONFIG = 0x15 ; +const uint8_t RS_PKT_SUBTYPE_DISTANT_CHAT_DH_PUBLIC_KEY = 0x16 ; +const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_SIGNED_MSG = 0x17 ; +const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_SIGNED_EVENT = 0x18 ; +const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_LIST = 0x19 ; +const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_INVITE = 0x1A ; + +typedef uint64_t ChatLobbyId ; +typedef uint64_t ChatLobbyMsgId ; +typedef std::string ChatLobbyNickName ; +typedef uint64_t DistantChatDHSessionId ; + +class RsChatItem: public RsItem +{ + public: + RsChatItem(uint8_t chat_subtype) : RsItem(RS_PKT_VERSION_SERVICE,RS_SERVICE_TYPE_CHAT,chat_subtype) + { + setPriorityLevel(QOS_PRIORITY_RS_CHAT_ITEM) ; + } + + virtual ~RsChatItem() {} + virtual void clear() {} + virtual std::ostream& print(std::ostream &out, uint16_t indent = 0) = 0 ; + + virtual bool serialise(void *data,uint32_t& size) = 0 ; // Isn't it better that items can serialize themselves ? + virtual uint32_t serial_size() = 0 ; // deserialise is handled using a constructor +}; + +/*! + * For sending chat msgs + * @see p3ChatService + */ +class RsChatMsgItem: public RsChatItem +{ +public: + RsChatMsgItem() :RsChatItem(RS_PKT_SUBTYPE_DEFAULT) {} + RsChatMsgItem(uint8_t subtype) :RsChatItem(subtype) {} + + RsChatMsgItem(void *data,uint32_t size,uint8_t subtype = RS_PKT_SUBTYPE_DEFAULT) ; // deserialization + + virtual ~RsChatMsgItem() {} + 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 + + uint32_t chatFlags; + uint32_t sendTime; + std::string message; + + /* not serialised */ + uint32_t recvTime; +}; + +// This class contains the info to bounce an object throughout a lobby, while +// maintaining cache info to avoid duplicates. +// +class RsChatLobbyBouncingObject +{ +public: + ChatLobbyId lobby_id ; + ChatLobbyMsgId msg_id ; + ChatLobbyNickName nick ; // Nickname of sender + + RsTlvKeySignature signature ; + + virtual RsChatLobbyBouncingObject *duplicate() const = 0 ; + virtual std::ostream& print(std::ostream &out, uint16_t indent = 0); + + // returns the size in bytes of the data chunk to sign. + + virtual uint32_t signed_serial_size() =0; + virtual bool serialise_signed_part(void *data,uint32_t& size) = 0; + +protected: + // The functions below handle the serialisation of data that is specific to the bouncing object level. + // They are called by serial_size() and serialise() from children, but should not overload the serial_size() and + // serialise() methods, otherwise the wrong method will be called when serialising from this top level class. + + uint32_t serialized_size(bool include_signature) ; + bool serialise_to_memory(void *data,uint32_t tlvsize,uint32_t& offset,bool include_signature) ; + bool deserialise_from_memory(void *data,uint32_t rssize,uint32_t& offset) ; +}; + +class RsChatLobbyMsgItem: public RsChatMsgItem, public RsChatLobbyBouncingObject +{ +public: + RsChatLobbyMsgItem() :RsChatMsgItem(RS_PKT_SUBTYPE_CHAT_LOBBY_SIGNED_MSG) {} + + RsChatLobbyMsgItem(void *data,uint32_t size) ; // deserialization /// TODO!!! + + virtual ~RsChatLobbyMsgItem() {} + virtual std::ostream& print(std::ostream &out, uint16_t indent = 0); + virtual RsChatLobbyBouncingObject *duplicate() const { return new RsChatLobbyMsgItem(*this) ; } + + 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 + + virtual uint32_t signed_serial_size() ; + virtual bool serialise_signed_part(void *data,uint32_t& size) ;// Isn't it better that items can serialize themselves ? + + ChatLobbyMsgId parent_msg_id ; // Used for threaded chat. +}; + +class RsChatLobbyEventItem: public RsChatItem, public RsChatLobbyBouncingObject +{ + public: + RsChatLobbyEventItem() :RsChatItem(RS_PKT_SUBTYPE_CHAT_LOBBY_SIGNED_EVENT) {} + RsChatLobbyEventItem(void *data,uint32_t size) ; // deserialization /// TODO!!! + + virtual ~RsChatLobbyEventItem() {} + virtual std::ostream& print(std::ostream &out, uint16_t indent = 0); + virtual RsChatLobbyBouncingObject *duplicate() const { return new RsChatLobbyEventItem(*this) ; } + // + virtual bool serialise(void *data,uint32_t& size) ; + virtual uint32_t serial_size() ; + + virtual uint32_t signed_serial_size() ; + virtual bool serialise_signed_part(void *data,uint32_t& size) ; + + // members. + // + uint8_t event_type ; // used for defining the type of event. + std::string string1; // used for any string + uint32_t sendTime; // used to check for old looping messages +}; + +class RsChatLobbyListRequestItem: public RsChatItem +{ + public: + RsChatLobbyListRequestItem() : RsChatItem(RS_PKT_SUBTYPE_CHAT_LOBBY_LIST_REQUEST) {} + RsChatLobbyListRequestItem(void *data,uint32_t size) ; + virtual ~RsChatLobbyListRequestItem() {} + + virtual bool serialise(void *data,uint32_t& size) ; + virtual uint32_t serial_size() ; + + virtual std::ostream& print(std::ostream &out, uint16_t indent = 0); +}; + +struct VisibleChatLobbyInfo +{ + ChatLobbyId id ; + std::string name ; + std::string topic ; + uint32_t count ; + ChatLobbyFlags flags ; +}; + +class RsChatLobbyListItem: public RsChatItem +{ + public: + RsChatLobbyListItem() : RsChatItem(RS_PKT_SUBTYPE_CHAT_LOBBY_LIST) {} + RsChatLobbyListItem(void *data,uint32_t size) ; + virtual ~RsChatLobbyListItem() {} + + virtual std::ostream& print(std::ostream &out, uint16_t indent = 0); + + virtual bool serialise(void *data,uint32_t& size) ; + virtual uint32_t serial_size() ; + + std::vector lobbies ; +}; + +class RsChatLobbyUnsubscribeItem: public RsChatItem +{ + public: + RsChatLobbyUnsubscribeItem() :RsChatItem(RS_PKT_SUBTYPE_CHAT_LOBBY_UNSUBSCRIBE) {} + RsChatLobbyUnsubscribeItem(void *data,uint32_t size) ; // deserialization + + virtual ~RsChatLobbyUnsubscribeItem() {} + virtual std::ostream& print(std::ostream &out, uint16_t indent = 0); + + uint64_t lobby_id ; + + 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 +}; + +class RsChatLobbyConnectChallengeItem: public RsChatItem +{ + public: + RsChatLobbyConnectChallengeItem() :RsChatItem(RS_PKT_SUBTYPE_CHAT_LOBBY_CHALLENGE) {} + RsChatLobbyConnectChallengeItem(void *data,uint32_t size) ; // deserialization + + virtual ~RsChatLobbyConnectChallengeItem() {} + virtual std::ostream& print(std::ostream &out, uint16_t indent = 0); + + uint64_t challenge_code ; + + 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 +}; + +class RsChatLobbyInviteItem: public RsChatItem +{ + public: + RsChatLobbyInviteItem() :RsChatItem(RS_PKT_SUBTYPE_CHAT_LOBBY_INVITE) {} + RsChatLobbyInviteItem(void *data,uint32_t size) ; // deserialization + + virtual ~RsChatLobbyInviteItem() {} + virtual std::ostream& print(std::ostream &out, uint16_t indent = 0); + + ChatLobbyId lobby_id ; + std::string lobby_name ; + std::string lobby_topic ; + ChatLobbyFlags lobby_flags ; + + 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 +}; + +/*! + * For saving incoming and outgoing chat msgs + * @see p3ChatService + */ +class RsPrivateChatMsgConfigItem: public RsChatItem +{ + public: + RsPrivateChatMsgConfigItem() :RsChatItem(RS_PKT_SUBTYPE_PRIVATECHATMSG_CONFIG) {} + RsPrivateChatMsgConfigItem(void *data,uint32_t size) ; // deserialization + + virtual ~RsPrivateChatMsgConfigItem() {} + 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 + + /* set data from RsChatMsgItem to RsPrivateChatMsgConfigItem */ + void set(RsChatMsgItem *ci, const RsPeerId &peerId, uint32_t confFlags); + /* get data from RsPrivateChatMsgConfigItem to RsChatMsgItem */ + void get(RsChatMsgItem *ci); + + RsPeerId configPeerId; + uint32_t chatFlags; + uint32_t configFlags; + uint32_t sendTime; + std::string 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] ; + RsFileHash hash ; + std::string encrypted_radix64_string ; + RsPgpId destination_pgp_id ; + uint32_t time_of_validity ; + uint32_t last_hit_time ; + uint32_t flags ; +}; +class RsChatLobbyConfigItem: public RsChatItem +{ +public: + RsChatLobbyConfigItem() :RsChatItem(RS_PKT_SUBTYPE_CHAT_LOBBY_CONFIG) { lobby_Id = 0; } + RsChatLobbyConfigItem(void *data,uint32_t size) ; // deserialization + + virtual ~RsChatLobbyConfigItem() {} + + virtual void clear() { lobby_Id = 0; } + 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 + + uint64_t lobby_Id; + uint32_t flags ; +}; + +// This class contains activity info for the sending peer: active, idle, typing, etc. +// +class RsChatStatusItem: public RsChatItem +{ + public: + RsChatStatusItem() :RsChatItem(RS_PKT_SUBTYPE_CHAT_STATUS) {} + RsChatStatusItem(void *data,uint32_t size) ; // deserialization + + virtual ~RsChatStatusItem() {} + 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 + + uint32_t flags ; + std::string status_string; +}; + +// This class contains avatar images in Qt format. +// +class RsChatAvatarItem: public RsChatItem +{ + public: + RsChatAvatarItem() :RsChatItem(RS_PKT_SUBTYPE_CHAT_AVATAR) {setPriorityLevel(QOS_PRIORITY_RS_CHAT_AVATAR_ITEM) ;} + RsChatAvatarItem(void *data,uint32_t size) ; // deserialization + + virtual ~RsChatAvatarItem() ; + 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 + + uint32_t image_size ; // size of data in bytes + unsigned char *image_data ; // image +}; + +// This class contains the public Diffie-Hellman parameters to be sent +// when performing a DH agreement over a distant chat tunnel. +// +class RsChatDHPublicKeyItem: public RsChatItem +{ + public: + RsChatDHPublicKeyItem() :RsChatItem(RS_PKT_SUBTYPE_DISTANT_CHAT_DH_PUBLIC_KEY) {setPriorityLevel(QOS_PRIORITY_RS_CHAT_ITEM) ;} + RsChatDHPublicKeyItem(void *data,uint32_t size) ; // deserialization + + virtual ~RsChatDHPublicKeyItem() { BN_free(public_key) ; } + 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 + + // Private data to DH public key item + // + BIGNUM *public_key ; + + RsTlvKeySignature signature ; // signs the public key in a row. + RsTlvSecurityKey gxs_key ; // public key of the signer + + private: + RsChatDHPublicKeyItem(const RsChatDHPublicKeyItem&) : RsChatItem(RS_PKT_SUBTYPE_DISTANT_CHAT_DH_PUBLIC_KEY) {} // make the object non copy-able + const RsChatDHPublicKeyItem& operator=(const RsChatDHPublicKeyItem&) { return *this ;} +}; + +class RsChatSerialiser: public RsSerialType +{ + public: + RsChatSerialiser() :RsSerialType(RS_PKT_VERSION_SERVICE, RS_SERVICE_TYPE_CHAT) {} + + virtual uint32_t size (RsItem *item) + { + return static_cast(item)->serial_size() ; + } + virtual bool serialise(RsItem *item, void *data, uint32_t *size) + { + return static_cast(item)->serialise(data,*size) ; + } + virtual RsItem *deserialise (void *data, uint32_t *size) ; +}; + diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index 18ded24a5..646c65778 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -757,6 +757,14 @@ gxs { services/p3gxsreputation.cc \ serialiser/rsgxsreputationitems.cc \ + # GxsTunnel service + HEADERS += gxstunnel/p3gxstunnel.h \ + gxstunnel/rsgxstunnelitems.h \ + retroshare/rsgxstunnel.h + + SOURCES += gxstunnel/p3gxstunnel.cc \ + gxstunnel/rsgxstunnelitems.cc + # GxsCircles Service HEADERS += services/p3gxscircles.h \ serialiser/rsgxscircleitems.h \ From 7bcbc70d21b63a22799b63b0fb0dc7cd6afa9e25 Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 17 Nov 2015 18:12:46 -0500 Subject: [PATCH 02/26] added interface file for gxs tunnel service --- libretroshare/src/retroshare/rsgxstunnel.h | 98 ++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 libretroshare/src/retroshare/rsgxstunnel.h diff --git a/libretroshare/src/retroshare/rsgxstunnel.h b/libretroshare/src/retroshare/rsgxstunnel.h new file mode 100644 index 000000000..8645f587c --- /dev/null +++ b/libretroshare/src/retroshare/rsgxstunnel.h @@ -0,0 +1,98 @@ +/* + * libretroshare/src/services: rsgrouter.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". + * + */ + +#pragma once + +#include "util/rsdir.h" +#include "retroshare/rsids.h" +#include "retroshare/rsgxsifacetypes.h" + +class RsGxsTunnelService +{ +public: + class RsGxsTunnelClientService + { + public: + // The client should derive this in order to handle notifications from the tunnel service. + // This cannot be ignored because the client needs to know when the tunnel is active. + + virtual void notifyTunnelStatus(const RsGxsId& id,uint32_t tunnel_status) =0; + + // Data obtained from the corresponding GXS id. The memory ownership is transferred to the client, which + // is responsible to free it using free() once used. + + virtual void receiveData(const RsGxsId& id,unsigned char *data,uint32_t data_size) =0; + }; + + class GxsTunnelInfo + { + public: + RsGxsId gxs_id ; // GXS Id to which we're talking + uint32_t tunnel_status ; // active, requested, DH pending, etc. + uint32_t pending_data_packets; // number of packets not acknowledged by other side, still on their way. + uint32_t total_size_sent ; // total number bytes sent through that tunnel since openned. + uint32_t total_packets_sent ; // total number of packets sent and acknowledged by other side + + std::vector client_services ; + }; + + // This is the interface file for the secured tunnel service + // + //===================================================// + // Debugging info // + //===================================================// + + virtual bool getGxsTunnelsInfo(std::vector& infos) =0; + + // retrieve the routing probabilities + + //===================================================// + // Communication to other services. // + //===================================================// + + // Asks for a tunnel. The service will request it to turtle router, and exchange a AES key using DH. + // When the tunnel is secured, the client---here supplied as argument---will be notified. He can + // then send data into the tunnel. The same tunnel may be used by different clients. + + virtual bool requestSecuredTunnel(const RsGxsId& to_id,RsGxsTunnelClientService *client) =0 ; + + // Data is sent through the established tunnel, possibly multiple times, until reception is acknowledged + + virtual bool sendData(const RsGxsId& destination, const GRouterServiceId& client_id, const uint8_t *data, uint32_t data_size, const RsGxsId& signing_id, GRouterMsgPropagationId& id) =0; + + // Removes any established tunnel to this GXS id. This makes the tunnel refuse further data, but the tunnel will be however kept alive + // until all pending data is flushed. All clients attached to the tunnel will be notified that the tunnel gets closed. + + virtual bool removeExistingTunnel(const RsGxsId& to_id) =0; + + //===================================================// + // Routage feedback from other services // + //===================================================// + +}; + +// To access the GRouter from anywhere +// +extern RsGxsTunnelService *rsGxsTunnel ; From cb97ce6f728e051f2fb2b69690fa53a01e339663 Mon Sep 17 00:00:00 2001 From: csoler Date: Wed, 18 Nov 2015 23:56:35 -0500 Subject: [PATCH 03/26] half-way through GxsTunnel service --- libretroshare/src/gxstunnel/p3gxstunnel.cc | 173 +++++--- libretroshare/src/gxstunnel/p3gxstunnel.h | 3 +- .../src/gxstunnel/rsgxstunnelitems.h | 385 +++--------------- libretroshare/src/serialiser/rsserviceids.h | 39 +- 4 files changed, 191 insertions(+), 409 deletions(-) diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.cc b/libretroshare/src/gxstunnel/p3gxstunnel.cc index a62e8e5b2..b43aa7ff8 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.cc +++ b/libretroshare/src/gxstunnel/p3gxstunnel.cc @@ -51,6 +51,13 @@ static const uint32_t RS_GXS_TUNNEL_DH_STATUS_UNINITIALIZED = 0x0000 ; static const uint32_t RS_GXS_TUNNEL_DH_STATUS_HALF_KEY_DONE = 0x0001 ; static const uint32_t RS_GXS_TUNNEL_DH_STATUS_KEY_AVAILABLE = 0x0002 ; +static const uint32_t RS_GXS_TUNNEL_STATUS_UNKNOWN = 0x00 ; +static const uint32_t RS_GXS_TUNNEL_STATUS_CAN_TALK = 0x01 ; +static const uint32_t RS_GXS_TUNNEL_STATUS_TUNNEL_DN = 0x02 ; + +static const uint32_t GXS_TUNNEL_HMAC_SIZE = SHA_DIGEST_LENGTH ; +static const uint32_t GXS_TUNNEL_IV_SIZE = 8 ; + void p3GxsTunnelService::connectToTurtleRouter(p3turtle *tr) { mTurtle = tr ; @@ -93,7 +100,7 @@ void p3GxsTunnelService::flush() } if(it->second.last_keep_alive_sent + GXS_TUNNEL_KEEP_ALIVE_TIMEOUT < now && it->second.status == RS_GXS_TUNNEL_STATUS_CAN_TALK) { - RsChatStatusItem *cs = new RsChatStatusItem ; + RsGxsTunnelStatusItem *cs = new RsGxsTunnelStatusItem ; #warning should we send that unencrypted?? cs->status_string.clear() ; @@ -112,21 +119,26 @@ void p3GxsTunnelService::flush() } } -bool p3GxsTunnelService::handleRecvItem(RsChatItem *item) +bool p3GxsTunnelService::handleRecvItem(RsGxsTunnelItem *item) { if(item == NULL) return false ; switch(item->PacketSubType()) { - case RS_PKT_SUBTYPE_GXS_TUNNEL_DH_PUBLIC_KEY: handleRecvDHPublicKey(dynamic_cast(item)) ; break ; - return true ; + case RS_PKT_SUBTYPE_GXS_TUNNEL_DH_PUBLIC_KEY: handleRecvDHPublicKey(dynamic_cast(item)) ; break ; + return true ; - case RS_PKT_SUBTYPE_GXS_TUNNEL_STATUS: - { - // Keep alive packets should not be forwarded to the GUI. It's just for keeping the tunnel up. - - return true ; +#warning need to implement tunnel data handling here + case RS_PKT_SUBTYPE_GXS_TUNNEL_DATA: + return true ; + +#warning need to implement tunnel data ACK handling here + case RS_PKT_SUBTYPE_GXS_TUNNEL_DATA_ACK: + return true ; + + case RS_PKT_SUBTYPE_GXS_TUNNEL_STATUS: handleRecvStatusItem(dynamic_cast(item)) ; + return true ; } default: @@ -135,7 +147,9 @@ bool p3GxsTunnelService::handleRecvItem(RsChatItem *item) return false ; } -bool p3GxsTunnelService::handleOutgoingItem(RsChatItem *item) + +#warning is this function still used?? +bool p3GxsTunnelService::handleOutgoingItem(RsGxsTunnelItem *item) { { RS_STACK_MUTEX(mGxsTunnelMtx) ; @@ -147,7 +161,7 @@ bool p3GxsTunnelService::handleOutgoingItem(RsChatItem *item) } #ifdef CHAT_DEBUG - std::cerr << "p3ChatService::handleOutgoingItem(): sending to " << item->PeerId() << ": interpreted as a distant chat virtual peer id." << std::endl; + std::cerr << "p3GxsTunnelService::handleOutgoingItem(): sending to " << item->PeerId() << ": interpreted as a distant chat virtual peer id." << std::endl; #endif sendTurtleData(item) ; return true; @@ -161,7 +175,7 @@ void p3GxsTunnelService::handleRecvStatusItem(RsGxsTunnelStatusItem *cs) // nothing more to do, because the decryption routing will update the last_contact time when decrypting. if(cs->flags & RS_GXS_TUNNEL_FLAG_KEEP_ALIVE) - std::cerr << "GxsTunnelService::handleRecvChatStatusItem(): received keep alive packet for inactive tunnel! peerId=" << cs->PeerId() << std::endl; + std::cerr << "GxsTunnelService::handleRecvGxsTunnelStatusItem(): received keep alive packet for inactive tunnel! peerId=" << cs->PeerId() << std::endl; } bool p3GxsTunnelService::handleTunnelRequest(const RsFileHash& hash,const RsPeerId& /*peer_id*/) @@ -192,64 +206,64 @@ bool p3GxsTunnelService::handleTunnelRequest(const RsFileHash& hash,const RsPeer void p3GxsTunnelService::addVirtualPeer(const TurtleFileHash& hash,const TurtleVirtualPeerId& virtual_peer_id,RsTurtleGenericTunnelItem::Direction dir) { #ifdef DEBUG_GXS_TUNNEL - std::cerr << "GxsTunnelService:: received new virtual peer " << virtual_peer_id << " for hash " << hash << ", dir=" << dir << std::endl; + std::cerr << "GxsTunnelService:: received new virtual peer " << virtual_peer_id << " for hash " << hash << ", dir=" << dir << std::endl; #endif - RsGxsId own_gxs_id ; + RsGxsId own_gxs_id ; - { - RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + { + RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - GxsTunnelDHInfo& dhinfo( _gxs_tunnel_virtual_peer_ids[virtual_peer_id] ) ; - dhinfo.gxs_id.clear() ; + GxsTunnelDHInfo& dhinfo( _gxs_tunnel_virtual_peer_ids[virtual_peer_id] ) ; + dhinfo.gxs_id.clear() ; - if(dhinfo.dh != NULL) - DH_free(dhinfo.dh) ; + if(dhinfo.dh != NULL) + DH_free(dhinfo.dh) ; - dhinfo.dh = NULL ; - dhinfo.direction = dir ; - dhinfo.hash = hash ; - dhinfo.status = RS_GXS_TUNNEL_DH_STATUS_UNINITIALIZED ; + dhinfo.dh = NULL ; + dhinfo.direction = dir ; + dhinfo.hash = hash ; + dhinfo.status = RS_GXS_TUNNEL_DH_STATUS_UNINITIALIZED ; - if(dir == RsTurtleGenericTunnelItem::DIRECTION_CLIENT) - { - // check that a tunnel is not already working for this hash. If so, give up. + if(dir == RsTurtleGenericTunnelItem::DIRECTION_CLIENT) + { + // check that a tunnel is not already working for this hash. If so, give up. - own_gxs_id = gxsIdFromHash(hash) ; - } - else // client side - { - RsGxsId to_gxs_id = gxsIdFromHash(hash) ; - std::map::const_iterator it = _gxs_tunnel_contacts.find(to_gxs_id) ; + own_gxs_id = gxsIdFromHash(hash) ; + } + else // client side + { + RsGxsId to_gxs_id = gxsIdFromHash(hash) ; + std::map::const_iterator it = _gxs_tunnel_contacts.find(to_gxs_id) ; - if(it == _gxs_tunnel_contacts.end()) - { - std::cerr << "(EE) no pre-registered peer for hash " << hash << " on client side. This is a bug." << std::endl; - return ; - } + if(it == _gxs_tunnel_contacts.end()) + { + std::cerr << "(EE) no pre-registered peer for hash " << hash << " on client side. This is a bug." << std::endl; + return ; + } - if(it->second.status == RS_GXS_TUNNEL_STATUS_CAN_TALK) - { - std::cerr << " virtual peer is for a distant chat session that is already openned and alive. Giving it up." << std::endl; - return ; - } + if(it->second.status == RS_GXS_TUNNEL_STATUS_CAN_TALK) + { + std::cerr << " virtual peer is for a distant chat session that is already openned and alive. Giving it up." << std::endl; + return ; + } - own_gxs_id = it->second.own_gxs_id ; - } + own_gxs_id = it->second.own_gxs_id ; + } #ifdef DEBUG_GXS_TUNNEL - std::cerr << " Creating new virtual peer ID entry and empty DH session key." << std::endl; + std::cerr << " Creating new virtual peer ID entry and empty DH session key." << std::endl; #endif - } + } #ifdef DEBUG_GXS_TUNNEL - std::cerr << " Adding virtual peer " << virtual_peer_id << " for chat hash " << hash << std::endl; + std::cerr << " Adding virtual peer " << virtual_peer_id << " for chat hash " << hash << std::endl; #endif - // Start a new DH session for this tunnel - RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + // Start a new DH session for this tunnel + RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - locked_restartDHSession(virtual_peer_id,own_gxs_id) ; + locked_restartDHSession(virtual_peer_id,own_gxs_id) ; } void p3GxsTunnelService::locked_restartDHSession(const RsPeerId& virtual_peer_id,const RsGxsId& own_gxs_id) @@ -350,8 +364,6 @@ void p3GxsTunnelService::receiveTurtleData(RsTurtleGenericTunnelItem *gitem,cons std::cerr << "(EE) item encrypted data stream is too small: size = " << item->data_size << std::endl; return ; } -#warning use flags here!! -#warning add a MAC to make sure the data is not forged if(*((uint64_t*)item->data_bytes) != 0) // WTF?? we should use flags { #ifdef DEBUG_GXS_TUNNEL @@ -392,6 +404,7 @@ void p3GxsTunnelService::receiveTurtleData(RsTurtleGenericTunnelItem *gitem,cons } } +// This function encrypts the given data and adds a MAC and an IV into a serialised memory chunk that is then sent through the tunnel. bool p3GxsTunnelService::handleEncryptedData(const uint8_t *data_bytes,uint32_t data_size,const TurtleFileHash& hash,const RsPeerId& virtual_peer_id) { @@ -409,7 +422,9 @@ bool p3GxsTunnelService::handleEncryptedData(const uint8_t *data_bytes,uint32_t { RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - uint32_t decrypted_size = RsAES::get_buffer_size(data_size-8); + uint32_t encrypted_size = data_size - GXS_TUNNEL_IV_SIZE - GXS_TUNNEL_HMAC_SIZE; + uint32_t decrypted_size = RsAES::get_buffer_size(encrypted_size); + uint8_t *encrypted_data = (uint8_t*)data_bytes+GXS_TUNNEL_IV_SIZE+GXS_TUNNEL_HMAC_SIZE; uint8_t *decrypted_data = new uint8_t[decrypted_size]; uint8_t aes_key[GXS_TUNNEL_AES_KEY_SIZE] ; @@ -434,11 +449,27 @@ bool p3GxsTunnelService::handleEncryptedData(const uint8_t *data_bytes,uint32_t #ifdef DEBUG_GXS_TUNNEL std::cerr << " Using IV: " << std::hex << *(uint64_t*)data_bytes << std::dec << std::endl; std::cerr << " Decrypted buffer size: " << decrypted_size << std::endl; - std::cerr << " key : " << Bin2Hex(aes_key,16) << ; std::cerr << std::endl; + std::cerr << " key : " << Bin2Hex(aes_key,GXS_TUNNEL_AES_KEY_SIZE) << ; std::cerr << std::endl; + std::cerr << " hmac : " << Bin2Hex((uint8_t*)data_bytes+GXS_TUNNEL_IV_SIZE,GXS_TUNNEL_HMAC_SIZE) << ; std::cerr << std::endl; std::cerr << " data : " << Bin2Hex((uint8_t*)data_bytes,data_size) << ; std::cerr << std::endl; #endif + // first, check the HMAC + + unsigned char *hm = HMAC(EVP_sha1(),aes_key,GXS_TUNNEL_AES_KEY_SIZE,encrypted_data,encrypted_size,NULL,NULL) ; + + if(memcmp(hm,&data_bytes[GXS_TUNNEL_IV_SIZE],GXS_TUNNEL_HMAC_SIZE)) + { + std::cerr << "(EE) packet HMAC does not match. Computed HMAC=" << Bin2Hex(md,GXS_TUNNEL_HMAC_SIZE) << std::endl; + std::cerr << "(EE) resetting new DH session." << std::endl; - if(!RsAES::aes_decrypt_8_16((uint8_t*)data_bytes+8,data_size-8,aes_key,(uint8_t*)data_bytes,decrypted_data,decrypted_size)) + delete[] decrypted_data ; + + locked_restartDHSession(virtual_peer_id,it2->second.own_gxs_id) ; + + return false ; + } + + if(!RsAES::aes_decrypt_8_16(encrypted_data,encrypted_size, aes_key,(uint8_t*)data_bytes,decrypted_data,decrypted_size)) { std::cerr << "(EE) packet decryption failed." << std::endl; std::cerr << "(EE) resetting new DH session." << std::endl; @@ -750,7 +781,9 @@ bool GxsTunnelService::locked_initDHSessionKey(DH *& dh) return true ; } -void p3GxsTunnelService::sendTurtleData(RsChatItem *item) +// Encrypts and sends the item. + +void p3GxsTunnelService::sendTurtleData(RsGxsTunnelItem *item) { #ifdef DEBUG_GXS_TUNNEL std::cerr << "GxsTunnelService::sendTurtleData(): try sending item " << (void*)item << " to peer " << item->PeerId() << std::endl; @@ -767,6 +800,7 @@ void p3GxsTunnelService::sendTurtleData(RsChatItem *item) gitem->data_size = rssize + 8 ; gitem->data_bytes = malloc(rssize+8) ; + // by convention, we use a IV of 0 for unencrypted data. memset(gitem->data_bytes,0,8) ; if(!item->serialise(&((uint8_t*)gitem->data_bytes)[8],rssize)) @@ -842,10 +876,6 @@ void p3GxsTunnelService::sendEncryptedTurtleData(const uint8_t *buff,uint32_t rs uint8_t *encrypted_data = new uint8_t[RsAES::get_buffer_size(rssize)]; uint32_t encrypted_size = RsAES::get_buffer_size(rssize); -#ifdef DEBUG_GXS_TUNNEL - std::cerr << " Using IV: " << std::hex << IV << std::dec << std::endl; - std::cerr << " Using Key: " << Bin2Hex(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; @@ -857,18 +887,27 @@ void p3GxsTunnelService::sendEncryptedTurtleData(const uint8_t *buff,uint32_t rs // RsTurtleGenericDataItem *gitem = new RsTurtleGenericDataItem ; - gitem->data_size = encrypted_size + 8 ; + gitem->data_size = encrypted_size + GXS_TUNNEL_ENCRYPTION_IV_SIZE + GXS_TUNNEL_HMAC_SIZE ; gitem->data_bytes = malloc(gitem->data_size) ; - memcpy(gitem->data_bytes ,&IV,8) ; - memcpy(& (((uint8_t*)gitem->data_bytes)[8]),encrypted_data,encrypted_size) ; + memcpy(& (((uint8_t*)gitem->data_bytes)[0] ,&IV,8) ; + unsigned int md_len = GXS_TUNNEL_HMAC_SIZE ; + HMAC(EVP_sha1(),aes_key,GXS_TUNNEL_AES_KEY_SIZE,encrypted_data,encrypted_size,&(((uint8_t*)gitem->data_bytes)[GXS_TUNNEL_IV_SIZE]),&md_len) ; + + memcpy(& (((uint8_t*)gitem->data_bytes)[GXS_TUNNEL_HMAC_SIZE+GXS_TUNNEL_IV_SIZE]),encrypted_data,encrypted_size) ; + delete[] encrypted_data ; +#ifdef DEBUG_GXS_TUNNEL + std::cerr << " Using IV: " << std::hex << IV << std::dec << std::endl; + std::cerr << " Using Key: " << Bin2Hex(aes_key,GXS_TUNNEL_AES_KEY_SIZE) ; std::cerr << std::endl; + std::cerr << " hmac: " << Bin2Hex(gitem->data_bytes,GXS_TUNNEL_HMAC_SIZE) ; +#endif #ifdef DEBUG_GXS_TUNNEL std::cerr << "GxsTunnelService::sendTurtleData(): Sending encrypted data to virtual peer: " << virtual_peer_id << std::endl; std::cerr << " gitem->data_size = " << gitem->data_size << std::endl; - std::cerr << " data = " << Bin2Hex(gitem->data_bytes,gitem->data_size) ; + std::cerr << " serialised data = " << Bin2Hex(gitem->data_bytes,gitem->data_size) ; std::cerr << std::endl; #endif @@ -946,11 +985,11 @@ void p3GxsTunnelService::startClientGxsTunnelConnection(const RsGxsId& to_gxs_id #warning check that this code should go. #ifdef TO_BE_REMOVED // spawn a status item so as to open the chat window. - RsChatMsgItem *item = new RsChatMsgItem; + RsGxsTunnelMsgItem *item = new RsGxsTunnelMsgItem; item->message = "[Starting distant chat. Please wait for secure tunnel to be established]" ; item->chatFlags = RS_CHAT_FLAG_PRIVATE ; item->PeerId(RsPeerId(to_gxs_id)) ; - handleRecvChatMsgItem(item) ; + handleRecvGxsTunnelMsgItem(item) ; #endif } diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.h b/libretroshare/src/gxstunnel/p3gxstunnel.h index c08c57690..a26ef6019 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.h +++ b/libretroshare/src/gxstunnel/p3gxstunnel.h @@ -27,6 +27,7 @@ #include #include +#include class RsGixs ; @@ -120,7 +121,7 @@ private: bool locked_sendDHPublicKey(const DH *dh, const RsGxsId& own_gxs_id, const RsPeerId& virtual_peer_id) ; bool locked_initDHSessionKey(DH *&dh); - GxsTunnelPeerId virtualPeerIdFromHash(const TurtleFileHash& hash) ; // ... and to a hash for p3turtle + TurtleVirtualPeerId virtualPeerIdFromHash(const TurtleFileHash& hash) ; // ... and to a hash for p3turtle // Comunication with Turtle service diff --git a/libretroshare/src/gxstunnel/rsgxstunnelitems.h b/libretroshare/src/gxstunnel/rsgxstunnelitems.h index 34c960d95..f2f4c0ef5 100644 --- a/libretroshare/src/gxstunnel/rsgxstunnelitems.h +++ b/libretroshare/src/gxstunnel/rsgxstunnelitems.h @@ -25,7 +25,6 @@ #pragma once -#include "openssl/bn.h" #include "retroshare/rstypes.h" #include "serialiser/rstlvkeys.h" #include "serialiser/rsserviceids.h" @@ -35,60 +34,26 @@ #include "serialiser/rstlvfileitem.h" /* chat Flags */ -const uint32_t RS_CHAT_FLAG_PRIVATE = 0x0001; -const uint32_t RS_CHAT_FLAG_REQUESTS_AVATAR = 0x0002; -const uint32_t RS_CHAT_FLAG_CONTAINS_AVATAR = 0x0004; -const uint32_t RS_CHAT_FLAG_AVATAR_AVAILABLE = 0x0008; -const uint32_t RS_CHAT_FLAG_CUSTOM_STATE = 0x0010; // used for transmitting peer status string -const uint32_t RS_CHAT_FLAG_PUBLIC = 0x0020; -const uint32_t RS_CHAT_FLAG_REQUEST_CUSTOM_STATE = 0x0040; -const uint32_t RS_CHAT_FLAG_CUSTOM_STATE_AVAILABLE = 0x0080; -const uint32_t RS_CHAT_FLAG_PARTIAL_MESSAGE = 0x0100; -const uint32_t RS_CHAT_FLAG_LOBBY = 0x0200; -const uint32_t RS_CHAT_FLAG_CLOSING_DISTANT_CONNECTION = 0x0400; -const uint32_t RS_CHAT_FLAG_ACK_DISTANT_CONNECTION = 0x0800; -const uint32_t RS_CHAT_FLAG_KEEP_ALIVE = 0x1000; +const uint32_t RS_GXS_TUNNEL_FLAG_CLOSING_DISTANT_CONNECTION = 0x0400; +const uint32_t RS_GXS_TUNNEL_FLAG_ACK_DISTANT_CONNECTION = 0x0800; +const uint32_t RS_GXS_TUNNEL_FLAG_KEEP_ALIVE = 0x1000; -const uint32_t RS_CHATMSG_CONFIGFLAG_INCOMING = 0x0001; +const uint8_t RS_PKT_SUBTYPE_GXS_TUNNEL_DATA = 0x01 ; +const uint8_t RS_PKT_SUBTYPE_GXS_TUNNEL_DH_PUBLIC_KEY = 0x02 ; +const uint8_t RS_PKT_SUBTYPE_GXS_TUNNEL_STATUS = 0x03 ; +const uint8_t RS_PKT_SUBTYPE_GXS_TUNNEL_DATA_ACK = 0x04 ; -const uint8_t RS_PKT_SUBTYPE_CHAT_AVATAR = 0x03 ; -const uint8_t RS_PKT_SUBTYPE_CHAT_STATUS = 0x04 ; -const uint8_t RS_PKT_SUBTYPE_PRIVATECHATMSG_CONFIG = 0x05 ; -const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_MSG_DEPRECATED = 0x06 ; // don't use ! Deprecated -const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_INVITE_DEPREC = 0x07 ; // don't use ! Deprecated -const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_ACCEPT = 0x08 ; -const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_CHALLENGE = 0x09 ; -const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_UNSUBSCRIBE = 0x0A ; -const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_EVENT_DEPREC = 0x0B ; // don't use ! Deprecated -const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_MSG = 0x0C ; // will be deprecated when only signed messages are accepted (02/2015) -const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_LIST_REQUEST = 0x0D ; -const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_LIST_deprecated = 0x0E ; // to be removed -const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_INVITE_deprecated = 0x0F ; // to be removed -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_deprecated3 = 0x12 ; -const uint8_t RS_PKT_SUBTYPE_DISTANT_INVITE_CONFIG = 0x13 ; -const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_CONFIG = 0x15 ; -const uint8_t RS_PKT_SUBTYPE_DISTANT_CHAT_DH_PUBLIC_KEY = 0x16 ; -const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_SIGNED_MSG = 0x17 ; -const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_SIGNED_EVENT = 0x18 ; -const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_LIST = 0x19 ; -const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_INVITE = 0x1A ; +typedef uint64_t GxsTunnelDHSessionId ; -typedef uint64_t ChatLobbyId ; -typedef uint64_t ChatLobbyMsgId ; -typedef std::string ChatLobbyNickName ; -typedef uint64_t DistantChatDHSessionId ; - -class RsChatItem: public RsItem +class RsGxsTunnelItem: public RsItem { public: - RsChatItem(uint8_t chat_subtype) : RsItem(RS_PKT_VERSION_SERVICE,RS_SERVICE_TYPE_CHAT,chat_subtype) + RsGxsTunnelItem(uint8_t item_subtype) : RsItem(RS_PKT_VERSION_SERVICE,RS_SERVICE_TYPE_GXS_TUNNEL,item_subtype) { setPriorityLevel(QOS_PRIORITY_RS_CHAT_ITEM) ; } - virtual ~RsChatItem() {} + virtual ~RsGxsTunnelItem() {} virtual void clear() {} virtual std::ostream& print(std::ostream &out, uint16_t indent = 0) = 0 ; @@ -96,305 +61,80 @@ class RsChatItem: public RsItem virtual uint32_t serial_size() = 0 ; // deserialise is handled using a constructor }; -/*! - * For sending chat msgs - * @see p3ChatService - */ -class RsChatMsgItem: public RsChatItem -{ -public: - RsChatMsgItem() :RsChatItem(RS_PKT_SUBTYPE_DEFAULT) {} - RsChatMsgItem(uint8_t subtype) :RsChatItem(subtype) {} +// /*! +// * For sending distant communication data. The item is not encrypted after being serialised, but the data it. +// * The MAC is computed over encrypted data using the PFS key. All other items (except DH keys) are serialised, encrypted, and +// * sent as data in a RsGxsTunnelDataItem. +// * +// * @see p3GxsTunnelService +// */ +// class RsGxsTunnelDataItem: public RsGxsTunnelItem +// { +// public: +// RsGxsTunnelDataItem() :RsGxsTunnelItem(RS_PKT_SUBTYPE_GXS_TUNNEL_DATA) {} +// RsGxsTunnelDataItem(uint8_t subtype) :RsGxsTunnelItem(subtype) {} +// +// virtual ~RsGxsTunnelDataItem() {} +// 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 +// +// uint32_t sendTime; +// uint32_t flags; // mainly NEEDS_HACK? +// unsigned char *data ; // encrypted data +// uint32_t data_size ; // encrypted data size +// unsigned char IV[IV_LENGTH] ; // IV for the encrypted data +// unsigned char encrypted_data_mac[SHA_DIGEST_LENGTH] ; // mac of the encrypted data, in order to avoid +// }; - RsChatMsgItem(void *data,uint32_t size,uint8_t subtype = RS_PKT_SUBTYPE_DEFAULT) ; // deserialization +// Used to send status of connection. This can be closing orders, flushing orders, etc. +// These items are always sent encrypted. - virtual ~RsChatMsgItem() {} - 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 - - uint32_t chatFlags; - uint32_t sendTime; - std::string message; - - /* not serialised */ - uint32_t recvTime; -}; - -// This class contains the info to bounce an object throughout a lobby, while -// maintaining cache info to avoid duplicates. -// -class RsChatLobbyBouncingObject -{ -public: - ChatLobbyId lobby_id ; - ChatLobbyMsgId msg_id ; - ChatLobbyNickName nick ; // Nickname of sender - - RsTlvKeySignature signature ; - - virtual RsChatLobbyBouncingObject *duplicate() const = 0 ; - virtual std::ostream& print(std::ostream &out, uint16_t indent = 0); - - // returns the size in bytes of the data chunk to sign. - - virtual uint32_t signed_serial_size() =0; - virtual bool serialise_signed_part(void *data,uint32_t& size) = 0; - -protected: - // The functions below handle the serialisation of data that is specific to the bouncing object level. - // They are called by serial_size() and serialise() from children, but should not overload the serial_size() and - // serialise() methods, otherwise the wrong method will be called when serialising from this top level class. - - uint32_t serialized_size(bool include_signature) ; - bool serialise_to_memory(void *data,uint32_t tlvsize,uint32_t& offset,bool include_signature) ; - bool deserialise_from_memory(void *data,uint32_t rssize,uint32_t& offset) ; -}; - -class RsChatLobbyMsgItem: public RsChatMsgItem, public RsChatLobbyBouncingObject -{ -public: - RsChatLobbyMsgItem() :RsChatMsgItem(RS_PKT_SUBTYPE_CHAT_LOBBY_SIGNED_MSG) {} - - RsChatLobbyMsgItem(void *data,uint32_t size) ; // deserialization /// TODO!!! - - virtual ~RsChatLobbyMsgItem() {} - virtual std::ostream& print(std::ostream &out, uint16_t indent = 0); - virtual RsChatLobbyBouncingObject *duplicate() const { return new RsChatLobbyMsgItem(*this) ; } - - 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 - - virtual uint32_t signed_serial_size() ; - virtual bool serialise_signed_part(void *data,uint32_t& size) ;// Isn't it better that items can serialize themselves ? - - ChatLobbyMsgId parent_msg_id ; // Used for threaded chat. -}; - -class RsChatLobbyEventItem: public RsChatItem, public RsChatLobbyBouncingObject -{ - public: - RsChatLobbyEventItem() :RsChatItem(RS_PKT_SUBTYPE_CHAT_LOBBY_SIGNED_EVENT) {} - RsChatLobbyEventItem(void *data,uint32_t size) ; // deserialization /// TODO!!! - - virtual ~RsChatLobbyEventItem() {} - virtual std::ostream& print(std::ostream &out, uint16_t indent = 0); - virtual RsChatLobbyBouncingObject *duplicate() const { return new RsChatLobbyEventItem(*this) ; } - // - virtual bool serialise(void *data,uint32_t& size) ; - virtual uint32_t serial_size() ; - - virtual uint32_t signed_serial_size() ; - virtual bool serialise_signed_part(void *data,uint32_t& size) ; - - // members. - // - uint8_t event_type ; // used for defining the type of event. - std::string string1; // used for any string - uint32_t sendTime; // used to check for old looping messages -}; - -class RsChatLobbyListRequestItem: public RsChatItem +class RsGxsTunnelStatusItem: public RsGxsTunnelItem { public: - RsChatLobbyListRequestItem() : RsChatItem(RS_PKT_SUBTYPE_CHAT_LOBBY_LIST_REQUEST) {} - RsChatLobbyListRequestItem(void *data,uint32_t size) ; - virtual ~RsChatLobbyListRequestItem() {} + RsGxsTunnelStatusItem() :RsGxsTunnelItem(RS_PKT_SUBTYPE_GXS_TUNNEL_STATUS) {} + RsGxsTunnelStatusItem(void *data,uint32_t size) ; // deserialization - virtual bool serialise(void *data,uint32_t& size) ; - virtual uint32_t serial_size() ; - - virtual std::ostream& print(std::ostream &out, uint16_t indent = 0); -}; - -struct VisibleChatLobbyInfo -{ - ChatLobbyId id ; - std::string name ; - std::string topic ; - uint32_t count ; - ChatLobbyFlags flags ; -}; - -class RsChatLobbyListItem: public RsChatItem -{ - public: - RsChatLobbyListItem() : RsChatItem(RS_PKT_SUBTYPE_CHAT_LOBBY_LIST) {} - RsChatLobbyListItem(void *data,uint32_t size) ; - virtual ~RsChatLobbyListItem() {} - - virtual std::ostream& print(std::ostream &out, uint16_t indent = 0); - - virtual bool serialise(void *data,uint32_t& size) ; - virtual uint32_t serial_size() ; - - std::vector lobbies ; -}; - -class RsChatLobbyUnsubscribeItem: public RsChatItem -{ - public: - RsChatLobbyUnsubscribeItem() :RsChatItem(RS_PKT_SUBTYPE_CHAT_LOBBY_UNSUBSCRIBE) {} - RsChatLobbyUnsubscribeItem(void *data,uint32_t size) ; // deserialization - - virtual ~RsChatLobbyUnsubscribeItem() {} - virtual std::ostream& print(std::ostream &out, uint16_t indent = 0); - - uint64_t lobby_id ; - - 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 -}; - -class RsChatLobbyConnectChallengeItem: public RsChatItem -{ - public: - RsChatLobbyConnectChallengeItem() :RsChatItem(RS_PKT_SUBTYPE_CHAT_LOBBY_CHALLENGE) {} - RsChatLobbyConnectChallengeItem(void *data,uint32_t size) ; // deserialization - - virtual ~RsChatLobbyConnectChallengeItem() {} - virtual std::ostream& print(std::ostream &out, uint16_t indent = 0); - - uint64_t challenge_code ; - - 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 -}; - -class RsChatLobbyInviteItem: public RsChatItem -{ - public: - RsChatLobbyInviteItem() :RsChatItem(RS_PKT_SUBTYPE_CHAT_LOBBY_INVITE) {} - RsChatLobbyInviteItem(void *data,uint32_t size) ; // deserialization - - virtual ~RsChatLobbyInviteItem() {} - virtual std::ostream& print(std::ostream &out, uint16_t indent = 0); - - ChatLobbyId lobby_id ; - std::string lobby_name ; - std::string lobby_topic ; - ChatLobbyFlags lobby_flags ; - - 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 -}; - -/*! - * For saving incoming and outgoing chat msgs - * @see p3ChatService - */ -class RsPrivateChatMsgConfigItem: public RsChatItem -{ - public: - RsPrivateChatMsgConfigItem() :RsChatItem(RS_PKT_SUBTYPE_PRIVATECHATMSG_CONFIG) {} - RsPrivateChatMsgConfigItem(void *data,uint32_t size) ; // deserialization - - virtual ~RsPrivateChatMsgConfigItem() {} - virtual void clear() {} + virtual ~RsGxsTunnelStatusItem() {} 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 + virtual uint32_t serial_size() ; // deserialise is handled using a constructor - /* set data from RsChatMsgItem to RsPrivateChatMsgConfigItem */ - void set(RsChatMsgItem *ci, const RsPeerId &peerId, uint32_t confFlags); - /* get data from RsPrivateChatMsgConfigItem to RsChatMsgItem */ - void get(RsChatMsgItem *ci); - - RsPeerId configPeerId; - uint32_t chatFlags; - uint32_t configFlags; - uint32_t sendTime; - std::string 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] ; - RsFileHash hash ; - std::string encrypted_radix64_string ; - RsPgpId destination_pgp_id ; - uint32_t time_of_validity ; - uint32_t last_hit_time ; uint32_t flags ; }; -class RsChatLobbyConfigItem: public RsChatItem -{ -public: - RsChatLobbyConfigItem() :RsChatItem(RS_PKT_SUBTYPE_CHAT_LOBBY_CONFIG) { lobby_Id = 0; } - RsChatLobbyConfigItem(void *data,uint32_t size) ; // deserialization - virtual ~RsChatLobbyConfigItem() {} +// Used to confirm reception of an encrypted item. - virtual void clear() { lobby_Id = 0; } - 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 - - uint64_t lobby_Id; - uint32_t flags ; -}; - -// This class contains activity info for the sending peer: active, idle, typing, etc. -// -class RsChatStatusItem: public RsChatItem +class RsGxsTunnelDataAckItem: public RsGxsTunnelItem { public: - RsChatStatusItem() :RsChatItem(RS_PKT_SUBTYPE_CHAT_STATUS) {} - RsChatStatusItem(void *data,uint32_t size) ; // deserialization + RsGxsTunnelDataAckItem() :RsGxsTunnelItem(RS_PKT_SUBTYPE_GXS_TUNNEL_DATA_ACK) {} + RsGxsTunnelDataAckItem(void *data,uint32_t size) ; // deserialization - virtual ~RsChatStatusItem() {} + virtual ~RsGxsTunnelDataAckItem() {} 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 + virtual uint32_t serial_size() ; // deserialise is handled using a constructor - uint32_t flags ; - std::string status_string; + Sha1CheckSum data_hash ; }; -// This class contains avatar images in Qt format. -// -class RsChatAvatarItem: public RsChatItem -{ - public: - RsChatAvatarItem() :RsChatItem(RS_PKT_SUBTYPE_CHAT_AVATAR) {setPriorityLevel(QOS_PRIORITY_RS_CHAT_AVATAR_ITEM) ;} - RsChatAvatarItem(void *data,uint32_t size) ; // deserialization - - virtual ~RsChatAvatarItem() ; - 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 - - uint32_t image_size ; // size of data in bytes - unsigned char *image_data ; // image -}; // This class contains the public Diffie-Hellman parameters to be sent // when performing a DH agreement over a distant chat tunnel. // -class RsChatDHPublicKeyItem: public RsChatItem +class RsGxsTunnelDHPublicKeyItem: public RsGxsTunnelItem { public: - RsChatDHPublicKeyItem() :RsChatItem(RS_PKT_SUBTYPE_DISTANT_CHAT_DH_PUBLIC_KEY) {setPriorityLevel(QOS_PRIORITY_RS_CHAT_ITEM) ;} - RsChatDHPublicKeyItem(void *data,uint32_t size) ; // deserialization + RsGxsTunnelDHPublicKeyItem() :RsGxsTunnelItem(RS_PKT_SUBTYPE_DISTANT_CHAT_DH_PUBLIC_KEY) {} + RsGxsTunnelDHPublicKeyItem(void *data,uint32_t size) ; // deserialization - virtual ~RsChatDHPublicKeyItem() { BN_free(public_key) ; } + virtual ~RsGxsTunnelDHPublicKeyItem() { BN_free(public_key) ; } 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 ? @@ -408,22 +148,23 @@ class RsChatDHPublicKeyItem: public RsChatItem RsTlvSecurityKey gxs_key ; // public key of the signer private: - RsChatDHPublicKeyItem(const RsChatDHPublicKeyItem&) : RsChatItem(RS_PKT_SUBTYPE_DISTANT_CHAT_DH_PUBLIC_KEY) {} // make the object non copy-able - const RsChatDHPublicKeyItem& operator=(const RsChatDHPublicKeyItem&) { return *this ;} + // make the object non copy-able + RsGxsTunnelDHPublicKeyItem(const RsGxsTunnelDHPublicKeyItem&) : RsGxsTunnelItem(RS_PKT_SUBTYPE_GXS_TUNNEL_DH_PUBLIC_KEY) {} + const RsGxsTunnelDHPublicKeyItem& operator=(const RsGxsTunnelDHPublicKeyItem&) { return *this ;} }; -class RsChatSerialiser: public RsSerialType +class RsGxsTunnelSerialiser: public RsSerialType { public: - RsChatSerialiser() :RsSerialType(RS_PKT_VERSION_SERVICE, RS_SERVICE_TYPE_CHAT) {} + RsGxsTunnelSerialiser() :RsSerialType(RS_PKT_VERSION_SERVICE, RS_SERVICE_TYPE_GXS_TUNNEL) {} virtual uint32_t size (RsItem *item) { - return static_cast(item)->serial_size() ; + return static_cast(item)->serial_size() ; } virtual bool serialise(RsItem *item, void *data, uint32_t *size) { - return static_cast(item)->serialise(data,*size) ; + return static_cast(item)->serialise(data,*size) ; } virtual RsItem *deserialise (void *data, uint32_t *size) ; }; diff --git a/libretroshare/src/serialiser/rsserviceids.h b/libretroshare/src/serialiser/rsserviceids.h index 3460008a8..b7d7b2fa1 100644 --- a/libretroshare/src/serialiser/rsserviceids.h +++ b/libretroshare/src/serialiser/rsserviceids.h @@ -38,32 +38,33 @@ */ /* These are Cache Only */ -const uint16_t RS_SERVICE_TYPE_FILE_INDEX = 0x0001; +const uint16_t RS_SERVICE_TYPE_FILE_INDEX = 0x0001; /* These are Services only */ -const uint16_t RS_SERVICE_TYPE_DISC = 0x0011; -const uint16_t RS_SERVICE_TYPE_CHAT = 0x0012; -const uint16_t RS_SERVICE_TYPE_MSG = 0x0013; -const uint16_t RS_SERVICE_TYPE_TURTLE = 0x0014; -const uint16_t RS_SERVICE_TYPE_TUNNEL = 0x0015; -const uint16_t RS_SERVICE_TYPE_HEARTBEAT = 0x0016; -const uint16_t RS_SERVICE_TYPE_FILE_TRANSFER = 0x0017; -const uint16_t RS_SERVICE_TYPE_GROUTER = 0x0018; +const uint16_t RS_SERVICE_TYPE_DISC = 0x0011; +const uint16_t RS_SERVICE_TYPE_CHAT = 0x0012; +const uint16_t RS_SERVICE_TYPE_MSG = 0x0013; +const uint16_t RS_SERVICE_TYPE_TURTLE = 0x0014; +const uint16_t RS_SERVICE_TYPE_TUNNEL = 0x0015; +const uint16_t RS_SERVICE_TYPE_HEARTBEAT = 0x0016; +const uint16_t RS_SERVICE_TYPE_FILE_TRANSFER = 0x0017; +const uint16_t RS_SERVICE_TYPE_GROUTER = 0x0018; -const uint16_t RS_SERVICE_TYPE_SERVICEINFO = 0x0020; +const uint16_t RS_SERVICE_TYPE_SERVICEINFO = 0x0020; /* Bandwidth Control */ -const uint16_t RS_SERVICE_TYPE_BWCTRL = 0x0021; -// New Mail Service (replace old Msg Service) -const uint16_t RS_SERVICE_TYPE_MAIL = 0x0022; -const uint16_t RS_SERVICE_TYPE_DIRECT_MAIL = 0x0023; -const uint16_t RS_SERVICE_TYPE_DISTANT_MAIL = 0x0024; -const uint16_t RS_SERVICE_TYPE_GWEMAIL_MAIL = 0x0025; +const uint16_t RS_SERVICE_TYPE_BWCTRL = 0x0021; +// New Mail Service (replace old Msg Service) +const uint16_t RS_SERVICE_TYPE_MAIL = 0x0022; +const uint16_t RS_SERVICE_TYPE_DIRECT_MAIL = 0x0023; +const uint16_t RS_SERVICE_TYPE_DISTANT_MAIL = 0x0024; +const uint16_t RS_SERVICE_TYPE_GWEMAIL_MAIL = 0x0025; const uint16_t RS_SERVICE_TYPE_SERVICE_CONTROL= 0x0026; -const uint16_t RS_SERVICE_TYPE_DISTANT_CHAT = 0x0027; +const uint16_t RS_SERVICE_TYPE_DISTANT_CHAT = 0x0027; +const uint16_t RS_SERVICE_TYPE_GXS_TUNNEL = 0x0028; // Non essential services. -const uint16_t RS_SERVICE_TYPE_BANLIST = 0x0101; -const uint16_t RS_SERVICE_TYPE_STATUS = 0x0102; +const uint16_t RS_SERVICE_TYPE_BANLIST = 0x0101; +const uint16_t RS_SERVICE_TYPE_STATUS = 0x0102; /* New Cache Services */ /* Rs Network Exchange Service */ From 8df9d4be04e8dc73409b72eba55d1a1e9a959cd3 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 22 Nov 2015 11:36:14 -0500 Subject: [PATCH 04/26] added some doc for tunnel service. Fixed a few function prototypes --- libretroshare/src/gxstunnel/p3gxstunnel.cc | 117 +++++++++--------- libretroshare/src/gxstunnel/p3gxstunnel.h | 48 +++++-- .../src/gxstunnel/rsgxstunnelitems.h | 2 +- libretroshare/src/retroshare/rsgxstunnel.h | 35 ++++-- libretroshare/src/util/rsprint.cc | 4 + libretroshare/src/util/rsprint.h | 1 + 6 files changed, 127 insertions(+), 80 deletions(-) diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.cc b/libretroshare/src/gxstunnel/p3gxstunnel.cc index b43aa7ff8..869326795 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.cc +++ b/libretroshare/src/gxstunnel/p3gxstunnel.cc @@ -31,6 +31,7 @@ #include "openssl/err.h" #include "util/rsaes.h" +#include "util/rsprint.h" #include #include @@ -51,12 +52,13 @@ static const uint32_t RS_GXS_TUNNEL_DH_STATUS_UNINITIALIZED = 0x0000 ; static const uint32_t RS_GXS_TUNNEL_DH_STATUS_HALF_KEY_DONE = 0x0001 ; static const uint32_t RS_GXS_TUNNEL_DH_STATUS_KEY_AVAILABLE = 0x0002 ; -static const uint32_t RS_GXS_TUNNEL_STATUS_UNKNOWN = 0x00 ; -static const uint32_t RS_GXS_TUNNEL_STATUS_CAN_TALK = 0x01 ; -static const uint32_t RS_GXS_TUNNEL_STATUS_TUNNEL_DN = 0x02 ; +static const uint32_t RS_GXS_TUNNEL_STATUS_UNKNOWN = 0x00 ; +static const uint32_t RS_GXS_TUNNEL_STATUS_CAN_TALK = 0x01 ; +static const uint32_t RS_GXS_TUNNEL_STATUS_TUNNEL_DN = 0x02 ; +static const uint32_t RS_GXS_TUNNEL_STATUS_REMOTELY_CLOSED = 0x03 ; -static const uint32_t GXS_TUNNEL_HMAC_SIZE = SHA_DIGEST_LENGTH ; -static const uint32_t GXS_TUNNEL_IV_SIZE = 8 ; +static const uint32_t GXS_TUNNEL_ENCRYPTION_HMAC_SIZE = SHA_DIGEST_LENGTH ; +static const uint32_t GXS_TUNNEL_ENCRYPTION_IV_SIZE = 8 ; void p3GxsTunnelService::connectToTurtleRouter(p3turtle *tr) { @@ -70,7 +72,7 @@ void p3GxsTunnelService::flush() // while(!pendingGxsTunnelItems.empty()) { - sendTurtleData( pendingGxsTunnelItems.front() ) ; + sendTurtleData(pendingGxsTunnelItems.front() ) ; pendingGxsTunnelItems.pop_front() ; } @@ -102,9 +104,7 @@ void p3GxsTunnelService::flush() { RsGxsTunnelStatusItem *cs = new RsGxsTunnelStatusItem ; -#warning should we send that unencrypted?? - cs->status_string.clear() ; - cs->flags = RS_CHAT_FLAG_PRIVATE | RS_CHAT_FLAG_KEEP_ALIVE; + cs->flags = RS_GXS_TUNNEL_FLAG_KEEP_ALIVE; cs->PeerId(RsPeerId(it->first)) ; // we send off-mutex to avoid deadlock. @@ -119,7 +119,7 @@ void p3GxsTunnelService::flush() } } -bool p3GxsTunnelService::handleRecvItem(RsGxsTunnelItem *item) +bool p3GxsTunnelService::handleIncomingItem(RsGxsTunnelItem *item) { if(item == NULL) return false ; @@ -139,7 +139,6 @@ bool p3GxsTunnelService::handleRecvItem(RsGxsTunnelItem *item) case RS_PKT_SUBTYPE_GXS_TUNNEL_STATUS: handleRecvStatusItem(dynamic_cast(item)) ; return true ; - } default: return false ; @@ -148,24 +147,24 @@ bool p3GxsTunnelService::handleRecvItem(RsGxsTunnelItem *item) return false ; } -#warning is this function still used?? -bool p3GxsTunnelService::handleOutgoingItem(RsGxsTunnelItem *item) -{ - { - RS_STACK_MUTEX(mGxsTunnelMtx) ; - - std::map::const_iterator it=_gxs_tunnel_contacts.find(RsGxsId(item->PeerId())); - - if(it == _gxs_tunnel_contacts.end()) - return false ; - } - -#ifdef CHAT_DEBUG - std::cerr << "p3GxsTunnelService::handleOutgoingItem(): sending to " << item->PeerId() << ": interpreted as a distant chat virtual peer id." << std::endl; -#endif - sendTurtleData(item) ; - return true; -} +//#warning is this function still used?? +//bool p3GxsTunnelService::handleOutgoingItem(RsGxsTunnelItem *item) +//{ +// { +// RS_STACK_MUTEX(mGxsTunnelMtx) ; +// +// std::map::const_iterator it=_gxs_tunnel_contacts.find(RsGxsId(item->PeerId())); +// +// if(it == _gxs_tunnel_contacts.end()) +// return false ; +// } +// +//#ifdef CHAT_DEBUG +// std::cerr << "p3GxsTunnelService::handleOutgoingItem(): sending to " << item->PeerId() << ": interpreted as a distant chat virtual peer id." << std::endl; +//#endif +// sendTurtleData(item) ; +// return true; +//} void p3GxsTunnelService::handleRecvStatusItem(RsGxsTunnelStatusItem *cs) { @@ -383,7 +382,7 @@ void p3GxsTunnelService::receiveTurtleData(RsTurtleGenericTunnelItem *gitem,cons // Now try deserialise the decrypted data to make an RsItem out of it. // #warning needs proper passing of item to client - //RsItem *citem = RsChatSerialiser().deserialise(&((uint8_t*)item->data_bytes)[8],&item->data_size) ; + RsItem *citem = RsGxsTunnelSerialiser().deserialise(&((uint8_t*)item->data_bytes)[8],&item->data_size-8) ; if(citem == NULL) { @@ -397,7 +396,7 @@ void p3GxsTunnelService::receiveTurtleData(RsTurtleGenericTunnelItem *gitem,cons if(dynamic_cast(citem) != NULL) { citem->PeerId(virtual_peer_id) ; - handleIncomingItem(citem) ; + handleIncomingItem(dynamic_cast(citem)) ; } else std::cerr << "(EE) Deserialiased item has unexpected type." << std::endl; @@ -413,18 +412,18 @@ bool p3GxsTunnelService::handleEncryptedData(const uint8_t *data_bytes,uint32_t std::cerr << " size = " << data_size << std::endl; std::cerr << " data = " << (void*)data_bytes << std::endl; std::cerr << " IV = " << std::hex << *(uint64_t*)data_bytes << std::dec << std::endl; - std::cerr << " data = " << Bin2Hex((uint8_t*)data_bytes,data_size) ; + std::cerr << " data = " << RsUtil::BinToHex((char*)data_bytes,data_size) ; std::cerr << std::endl; #endif - RsItem *citem = NULL; + RsGxsTunnelItem *citem = NULL; { RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - uint32_t encrypted_size = data_size - GXS_TUNNEL_IV_SIZE - GXS_TUNNEL_HMAC_SIZE; + uint32_t encrypted_size = data_size - GXS_TUNNEL_ENCRYPTION_IV_SIZE - GXS_TUNNEL_ENCRYPTION_HMAC_SIZE; uint32_t decrypted_size = RsAES::get_buffer_size(encrypted_size); - uint8_t *encrypted_data = (uint8_t*)data_bytes+GXS_TUNNEL_IV_SIZE+GXS_TUNNEL_HMAC_SIZE; + uint8_t *encrypted_data = (uint8_t*)data_bytes+GXS_TUNNEL_ENCRYPTION_IV_SIZE+GXS_TUNNEL_ENCRYPTION_HMAC_SIZE; uint8_t *decrypted_data = new uint8_t[decrypted_size]; uint8_t aes_key[GXS_TUNNEL_AES_KEY_SIZE] ; @@ -449,17 +448,17 @@ bool p3GxsTunnelService::handleEncryptedData(const uint8_t *data_bytes,uint32_t #ifdef DEBUG_GXS_TUNNEL std::cerr << " Using IV: " << std::hex << *(uint64_t*)data_bytes << std::dec << std::endl; std::cerr << " Decrypted buffer size: " << decrypted_size << std::endl; - std::cerr << " key : " << Bin2Hex(aes_key,GXS_TUNNEL_AES_KEY_SIZE) << ; std::cerr << std::endl; - std::cerr << " hmac : " << Bin2Hex((uint8_t*)data_bytes+GXS_TUNNEL_IV_SIZE,GXS_TUNNEL_HMAC_SIZE) << ; std::cerr << std::endl; - std::cerr << " data : " << Bin2Hex((uint8_t*)data_bytes,data_size) << ; std::cerr << std::endl; + std::cerr << " key : " << RsUtil::BinToHex((char*)aes_key,GXS_TUNNEL_AES_KEY_SIZE) << std::endl; + std::cerr << " hmac : " << RsUtil::BinToHex((char*)data_bytes+GXS_TUNNEL_ENCRYPTION_IV_SIZE,GXS_TUNNEL_ENCRYPTION_HMAC_SIZE) << std::endl; + std::cerr << " data : " << RsUtil::BinToHex((char*)data_bytes,data_size) << std::endl; #endif // first, check the HMAC unsigned char *hm = HMAC(EVP_sha1(),aes_key,GXS_TUNNEL_AES_KEY_SIZE,encrypted_data,encrypted_size,NULL,NULL) ; - if(memcmp(hm,&data_bytes[GXS_TUNNEL_IV_SIZE],GXS_TUNNEL_HMAC_SIZE)) + if(memcmp(hm,&data_bytes[GXS_TUNNEL_ENCRYPTION_IV_SIZE],GXS_TUNNEL_ENCRYPTION_HMAC_SIZE)) { - std::cerr << "(EE) packet HMAC does not match. Computed HMAC=" << Bin2Hex(md,GXS_TUNNEL_HMAC_SIZE) << std::endl; + std::cerr << "(EE) packet HMAC does not match. Computed HMAC=" << RsUtil::BinToHex((char*)hm,GXS_TUNNEL_ENCRYPTION_HMAC_SIZE) << std::endl; std::cerr << "(EE) resetting new DH session." << std::endl; delete[] decrypted_data ; @@ -489,8 +488,7 @@ bool p3GxsTunnelService::handleEncryptedData(const uint8_t *data_bytes,uint32_t // Now try deserialise the decrypted data to make an RsItem out of it. // -#warning pass on the serialised data directly to client (see what GRouter does) - //citem = RsChatSerialiser().deserialise(decrypted_data,&decrypted_size) ; + citem = RsGxsTunnelSerialiser().deserialiseGxsTunnelItem(decrypted_data,&decrypted_size) ; delete[] decrypted_data ; @@ -657,7 +655,7 @@ void p3GxsTunnelService::handleRecvDHPublicKey(RsGxsTunnelDHPublicKeyItem *item) #ifdef DEBUG_GXS_TUNNEL std::cerr << " DH key computed. Tunnel is now secured!" << std::endl; - std::cerr << " Key computed: " << Bin2Hex(pinfo.aes_key,16) << std::cerr << std::endl; + std::cerr << " Key computed: " << RsUtil::BinToHex((char*)pinfo.aes_key,16) << std::cerr << std::endl; std::cerr << " Sending a ACK packet." << std::endl; #endif @@ -678,7 +676,7 @@ void p3GxsTunnelService::handleRecvDHPublicKey(RsGxsTunnelDHPublicKeyItem *item) //RsServer::notify()->notifyListChange(NOTIFY_LIST_PRIVATE_INCOMING_CHAT, NOTIFY_TYPE_ADD); } -bool GxsTunnelService::locked_sendDHPublicKey(const DH *dh,const RsGxsId& own_gxs_id,const RsPeerId& virtual_peer_id) +bool p3GxsTunnelService::locked_sendDHPublicKey(const DH *dh,const RsGxsId& own_gxs_id,const RsPeerId& virtual_peer_id) { if(dh == NULL) { @@ -739,7 +737,7 @@ bool GxsTunnelService::locked_sendDHPublicKey(const DH *dh,const RsGxsId& own_gx return true ; } -bool GxsTunnelService::locked_initDHSessionKey(DH *& dh) +bool p3GxsTunnelService::locked_initDHSessionKey(DH *& dh) { // We use our own DH group prime. This has been generated with command-line openssl and checked. @@ -795,7 +793,7 @@ void p3GxsTunnelService::sendTurtleData(RsGxsTunnelItem *item) // RsTurtleGenericDataItem *gitem = new RsTurtleGenericDataItem ; - uint32_t rssize = item->serial_size() ; + uint32_t rssize = item->serial_size() ; gitem->data_size = rssize + 8 ; gitem->data_bytes = malloc(rssize+8) ; @@ -814,7 +812,7 @@ void p3GxsTunnelService::sendTurtleData(RsGxsTunnelItem *item) #ifdef DEBUG_GXS_TUNNEL std::cerr << " GxsTunnelService::sendTurtleData(): Sending clear data to virtual peer: " << item->PeerId() << std::endl; std::cerr << " gitem->data_size = " << gitem->data_size << std::endl; - std::cerr << " data = " << Bin2Hex(gitem->data_bytes,gitem->data_size) ; + std::cerr << " data = " << RsUtil::BinToHex((char*)gitem->data_bytes,gitem->data_size) ; std::cerr << std::endl; #endif mTurtle->sendTurtleData(item->PeerId(),gitem) ; @@ -887,34 +885,34 @@ void p3GxsTunnelService::sendEncryptedTurtleData(const uint8_t *buff,uint32_t rs // RsTurtleGenericDataItem *gitem = new RsTurtleGenericDataItem ; - gitem->data_size = encrypted_size + GXS_TUNNEL_ENCRYPTION_IV_SIZE + GXS_TUNNEL_HMAC_SIZE ; + gitem->data_size = encrypted_size + GXS_TUNNEL_ENCRYPTION_IV_SIZE + GXS_TUNNEL_ENCRYPTION_HMAC_SIZE ; gitem->data_bytes = malloc(gitem->data_size) ; - memcpy(& (((uint8_t*)gitem->data_bytes)[0] ,&IV,8) ; + memcpy(& ((uint8_t*)gitem->data_bytes)[0] ,&IV,8) ; - unsigned int md_len = GXS_TUNNEL_HMAC_SIZE ; - HMAC(EVP_sha1(),aes_key,GXS_TUNNEL_AES_KEY_SIZE,encrypted_data,encrypted_size,&(((uint8_t*)gitem->data_bytes)[GXS_TUNNEL_IV_SIZE]),&md_len) ; + unsigned int md_len = GXS_TUNNEL_ENCRYPTION_HMAC_SIZE ; + HMAC(EVP_sha1(),aes_key,GXS_TUNNEL_AES_KEY_SIZE,encrypted_data,encrypted_size,&(((uint8_t*)gitem->data_bytes)[GXS_TUNNEL_ENCRYPTION_IV_SIZE]),&md_len) ; - memcpy(& (((uint8_t*)gitem->data_bytes)[GXS_TUNNEL_HMAC_SIZE+GXS_TUNNEL_IV_SIZE]),encrypted_data,encrypted_size) ; + memcpy(& (((uint8_t*)gitem->data_bytes)[GXS_TUNNEL_ENCRYPTION_HMAC_SIZE+GXS_TUNNEL_ENCRYPTION_IV_SIZE]),encrypted_data,encrypted_size) ; delete[] encrypted_data ; #ifdef DEBUG_GXS_TUNNEL std::cerr << " Using IV: " << std::hex << IV << std::dec << std::endl; - std::cerr << " Using Key: " << Bin2Hex(aes_key,GXS_TUNNEL_AES_KEY_SIZE) ; std::cerr << std::endl; - std::cerr << " hmac: " << Bin2Hex(gitem->data_bytes,GXS_TUNNEL_HMAC_SIZE) ; + std::cerr << " Using Key: " << RsUtil::BinToHex((char*)aes_key,GXS_TUNNEL_AES_KEY_SIZE) ; std::cerr << std::endl; + std::cerr << " hmac: " << RsUtil::BinToHex((char*)gitem->data_bytes,GXS_TUNNEL_ENCRYPTION_HMAC_SIZE) ; #endif #ifdef DEBUG_GXS_TUNNEL std::cerr << "GxsTunnelService::sendTurtleData(): Sending encrypted data to virtual peer: " << virtual_peer_id << std::endl; std::cerr << " gitem->data_size = " << gitem->data_size << std::endl; - std::cerr << " serialised data = " << Bin2Hex(gitem->data_bytes,gitem->data_size) ; + std::cerr << " serialised data = " << RsUtil::BinToHex((char*)gitem->data_bytes,gitem->data_size) ; std::cerr << std::endl; #endif mTurtle->sendTurtleData(virtual_peer_id,gitem) ; } -bool p3GxsTunnelService::initiateGxsTunnelConnexion(const RsGxsId& to_gxs_id,const RsGxsId& from_gxs_id,uint32_t& error_code) +bool p3GxsTunnelService::requestSecuredTunnel(const RsGxsId& to_gxs_id,const RsGxsId& from_gxs_id,RsGxsTunnelClientService *client,uint32_t& error_code) { // should be a parameter. @@ -932,6 +930,7 @@ bool p3GxsTunnelService::initiateGxsTunnelConnexion(const RsGxsId& to_gxs_id,con if(!found) { std::cerr << " (EE) Cannot start distant chat, since GXS id " << from_gxs_id << " is not available." << std::endl; + error_code = RS_GXS_TUNNEL_ERROR_UNKNOWN_GXS_ID ; return false ; } RsGxsId own_gxs_id = from_gxs_id ; @@ -1029,7 +1028,7 @@ RsGxsId p3GxsTunnelService::gxsIdFromHash(const TurtleFileHash& sum) return RsGxsId(sum.toByteArray());// takes the first 16 bytes } -bool p3GxsTunnelService::getGxsTunnelStatus(const RsGxsId& gxs_id,uint32_t& status, RsGxsId *from_gxs_id) +bool p3GxsTunnelService::getTunnelStatus(const RsGxsId& gxs_id,uint32_t& status, RsGxsId *from_gxs_id) { RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ @@ -1050,7 +1049,7 @@ bool p3GxsTunnelService::getGxsTunnelStatus(const RsGxsId& gxs_id,uint32_t& stat return false ; } -bool p3GxsTunnelService::closeGxsTunnelConnexion(const RsGxsId& gxs_id) +bool p3GxsTunnelService::closeExistingTunnel(const RsGxsId& gxs_id) { // two cases: // - client needs to stop asking for tunnels => remove the hash from the list of tunnelled files @@ -1082,7 +1081,7 @@ bool p3GxsTunnelService::closeGxsTunnelConnexion(const RsGxsId& gxs_id) RsGxsTunnelStatusItem *cs = new RsGxsTunnelStatusItem ; - cs->flags = RS_CHAT_FLAG_CLOSING_DISTANT_CONNECTION; + cs->flags = RS_GXS_TUNNEL_FLAG_CLOSING_DISTANT_CONNECTION; cs->PeerId(RsPeerId(gxs_id)); sendTurtleData(cs) ; // that needs to be done off-mutex and before we close the tunnel. diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.h b/libretroshare/src/gxstunnel/p3gxstunnel.h index a26ef6019..a33c60862 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.h +++ b/libretroshare/src/gxstunnel/p3gxstunnel.h @@ -3,7 +3,7 @@ * * Services for RetroShare. * - * Copyright 2014 by Cyril Soler + * Copyright 2015 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 @@ -25,6 +25,33 @@ #pragma once +// Generic tunnel service +// +// Preconditions: +// * multiple services can use the same tunnel +// * tunnels are automatically encrypted and ensure transport (items stored in a queue until ACKed by the other side) +// * each tunnel is associated to a specific GXS id on both sides. Consequently, services that request tunnels from different IDs to a +// server for the same GXS id need to be handled correctly. +// +// GUI +// * the GUI should show for each tunnel: +// - starting and ending GXS ids +// - tunnel status (DH ok, closed from distant peer, locally closed, etc) +// - amount of data that is transferred in the tunnel +// - number of pending items (and total size) +// - number ACKed items both ways. +// +// we can use an additional tab "Authenticated tunnels" in the statistics->turtle window +// +// Interaction with services: +// +// Services request tunnels from a given GXS id and to a given GXS id. When ready, they get a handle (virtual peer id) +// +// Services send data in the tunnel using the virtual peer id +// +// Data is send to a service ID (could be any existing service ID). The endpoint of the tunnel must register each service, in order to +// allow the data to be transmitted/sent from/to that service. Otherwise an error is issued. + #include #include #include @@ -42,20 +69,19 @@ public: mTurtle = NULL ; } - void flush() ; - virtual void connectToTurtleRouter(p3turtle *) ; // Creates the invite if the public key of the distant peer is available. // Om success, stores the invite in the map above, so that we can respond to tunnel requests. // - bool initiateTunnelConnexion(const RsGxsId& to_gxs_id,const RsGxsId &from_gxs_id, uint32_t &error_code) ; - bool closeTunnelConnexion(const RsGxsId& pid) ; + virtual bool requestSecuredTunnel(const RsGxsId& to_id,const RsGxsId& from_id,RsGxsTunnelClientService *client,uint32_t& error_code) ; + virtual bool closeExistingTunnel(const RsGxsId& pid) ; virtual bool getTunnelStatus(const RsGxsId &gxs_id,uint32_t &status, RsGxsId *from_gxs_id=NULL) ; - virtual void handleIncomingItem(RsItem *) ; - private: + void flush() ; + virtual bool handleIncomingItem(RsGxsTunnelItem *) ; + class GxsTunnelPeerInfo { public: @@ -95,7 +121,7 @@ private: // List of items to be sent asap. Used to store items that we cannot pass directly to // sendTurtleData(), because of Mutex protection. - std::list pendingDistantChatItems ; + std::list pendingGxsTunnelItems ; // Overloaded from RsTurtleClientService @@ -107,7 +133,7 @@ private: // session handling handles void markGxsTunnelAsClosed(const RsGxsId &gxs_id) ; - void startClientGxsTunnelConnection(const RsGxsId &to_gxs_id,const RsGxsId& from_gxs_id) ; + void startClientGxsTunnelConnection(const RsGxsId &to_gxs_id, const RsGxsId& from_gxs_id) ; void locked_restartDHSession(const RsPeerId &virtual_peer_id, const RsGxsId &own_gxs_id) ; // utility functions @@ -123,6 +149,10 @@ private: TurtleVirtualPeerId virtualPeerIdFromHash(const TurtleFileHash& hash) ; // ... and to a hash for p3turtle + // item handling + + void handleRecvStatusItem(RsGxsTunnelStatusItem *item) ; + // Comunication with Turtle service void sendTurtleData(RsGxsTunnelItem *) ; diff --git a/libretroshare/src/gxstunnel/rsgxstunnelitems.h b/libretroshare/src/gxstunnel/rsgxstunnelitems.h index f2f4c0ef5..3de2e207b 100644 --- a/libretroshare/src/gxstunnel/rsgxstunnelitems.h +++ b/libretroshare/src/gxstunnel/rsgxstunnelitems.h @@ -166,6 +166,6 @@ class RsGxsTunnelSerialiser: public RsSerialType { return static_cast(item)->serialise(data,*size) ; } - virtual RsItem *deserialise (void *data, uint32_t *size) ; + virtual RsGxsTunnelItem *deserialiseGxsTunnelItem(void *data, uint32_t *size) ; }; diff --git a/libretroshare/src/retroshare/rsgxstunnel.h b/libretroshare/src/retroshare/rsgxstunnel.h index 8645f587c..3024b96d7 100644 --- a/libretroshare/src/retroshare/rsgxstunnel.h +++ b/libretroshare/src/retroshare/rsgxstunnel.h @@ -27,11 +27,17 @@ #include "util/rsdir.h" #include "retroshare/rsids.h" +#include "retroshare/rsturtle.h" #include "retroshare/rsgxsifacetypes.h" class RsGxsTunnelService { public: + static const uint32_t RS_GXS_TUNNEL_ERROR_NO_ERROR = 0x0000 ; + static const uint32_t RS_GXS_TUNNEL_ERROR_UNKNOWN_GXS_ID = 0x0001 ; + + typedef TurtleVirtualPeerId RsGxsTunnelId ; + class RsGxsTunnelClientService { public: @@ -49,13 +55,19 @@ public: class GxsTunnelInfo { public: - RsGxsId gxs_id ; // GXS Id to which we're talking - uint32_t tunnel_status ; // active, requested, DH pending, etc. - uint32_t pending_data_packets; // number of packets not acknowledged by other side, still on their way. - uint32_t total_size_sent ; // total number bytes sent through that tunnel since openned. - uint32_t total_packets_sent ; // total number of packets sent and acknowledged by other side - - std::vector client_services ; + // Tunnel information + + RsGxsId destination_gxs_id ; // GXS Id we're talking to + RsGxsId source_gxs_id ; // GXS Id we're using to talk + uint32_t tunnel_status ; // active, requested, DH pending, etc. + uint32_t total_size_sent ; // total bytes sent through that tunnel since openned (including management). + uint32_t total_size_received ; // total bytes received through that tunnel since openned (including management). + + // Data packets + + uint32_t pending_data_packets; // number of packets not acknowledged by other side, still on their way. Should be 0 unless something bad happens. + uint32_t total_data_packets_sent ; // total number of data packets sent (does not include tunnel management) + uint32_t total_data_packets_received ; // total number of data packets received (does not include tunnel management) }; // This is the interface file for the secured tunnel service @@ -76,16 +88,17 @@ public: // When the tunnel is secured, the client---here supplied as argument---will be notified. He can // then send data into the tunnel. The same tunnel may be used by different clients. - virtual bool requestSecuredTunnel(const RsGxsId& to_id,RsGxsTunnelClientService *client) =0 ; + virtual bool requestSecuredTunnel(const RsGxsId& to_id,const RsGxsId& from_id,uint32_t& error_code) =0 ; - // Data is sent through the established tunnel, possibly multiple times, until reception is acknowledged + // Data is sent through the established tunnel, possibly multiple times, until reception is acknowledged. If the tunnel does not exist, the item is rejected and + // an error is issued. In any case, the memory ownership of the data is transferred to the tunnel service, so the client should not use it afterwards. - virtual bool sendData(const RsGxsId& destination, const GRouterServiceId& client_id, const uint8_t *data, uint32_t data_size, const RsGxsId& signing_id, GRouterMsgPropagationId& id) =0; + virtual bool sendData(RsGxsTunnelId tunnel_id, uint32_t client_service_id, const uint8_t *data, uint32_t data_size) =0; // Removes any established tunnel to this GXS id. This makes the tunnel refuse further data, but the tunnel will be however kept alive // until all pending data is flushed. All clients attached to the tunnel will be notified that the tunnel gets closed. - virtual bool removeExistingTunnel(const RsGxsId& to_id) =0; + virtual bool closeExistingTunnel(const RsGxsId& to_id) =0; //===================================================// // Routage feedback from other services // diff --git a/libretroshare/src/util/rsprint.cc b/libretroshare/src/util/rsprint.cc index 97848b3c0..0d0ec5a04 100644 --- a/libretroshare/src/util/rsprint.cc +++ b/libretroshare/src/util/rsprint.cc @@ -40,6 +40,10 @@ std::string RsUtil::BinToHex(const std::string &bin) return BinToHex(bin.c_str(), bin.length()); } +std::string RsUtil::BinToHex(const unsigned char *arr, const uint32_t len) +{ + return BinToHex((char*)arr,len) ; +} std::string RsUtil::BinToHex(const char *arr, const uint32_t len) { std::string out; diff --git a/libretroshare/src/util/rsprint.h b/libretroshare/src/util/rsprint.h index b5a370a49..9a1dbe7c3 100644 --- a/libretroshare/src/util/rsprint.h +++ b/libretroshare/src/util/rsprint.h @@ -35,6 +35,7 @@ namespace RsUtil { std::string BinToHex(const std::string &bin); std::string BinToHex(const char *arr, const uint32_t len); +std::string BinToHex(const unsigned char *arr, const uint32_t len); std::string HashId(const std::string &id, bool reverse = false); //std::string AccurateTimeString(); From 5c0f1dac088a16895e590a26458a66730e6e7086 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 22 Nov 2015 23:19:46 -0500 Subject: [PATCH 05/26] saving ongoing work. Implementation almoast finished. --- libretroshare/src/gxstunnel/p3gxstunnel.cc | 70 ++++++++++++++++------ libretroshare/src/gxstunnel/p3gxstunnel.h | 48 +++++++++++++-- libretroshare/src/retroshare/rsgxstunnel.h | 8 +-- libretroshare/src/retroshare/rsids.h | 2 + 4 files changed, 101 insertions(+), 27 deletions(-) diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.cc b/libretroshare/src/gxstunnel/p3gxstunnel.cc index 869326795..a619e9460 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.cc +++ b/libretroshare/src/gxstunnel/p3gxstunnel.cc @@ -82,11 +82,12 @@ void p3GxsTunnelService::flush() time_t now = time(NULL) ; - for(std::map::iterator it(_gxs_tunnel_contacts.begin());it!=_gxs_tunnel_contacts.end();++it) + for(std::map::iterator it(_gxs_tunnel_contacts.begin());it!=_gxs_tunnel_contacts.end();++it) { if(it->second.last_contact+20+GXS_TUNNEL_KEEP_ALIVE_TIMEOUT < now && it->second.status == RS_GXS_TUNNEL_STATUS_CAN_TALK) { std::cerr << "(II) GxsTunnelService:: connexion interrupted with peer." << std::endl; + it->second.status = RS_GXS_TUNNEL_STATUS_TUNNEL_DN ; it->second.virtual_peer_id.clear() ; @@ -232,7 +233,7 @@ void p3GxsTunnelService::addVirtualPeer(const TurtleFileHash& hash,const TurtleV else // client side { RsGxsId to_gxs_id = gxsIdFromHash(hash) ; - std::map::const_iterator it = _gxs_tunnel_contacts.find(to_gxs_id) ; + std::map::const_iterator it = _gxs_tunnel_contacts.find(to_gxs_id) ; if(it == _gxs_tunnel_contacts.end()) { @@ -273,6 +274,7 @@ void p3GxsTunnelService::locked_restartDHSession(const RsPeerId& virtual_peer_id GxsTunnelDHInfo& dhinfo = _gxs_tunnel_virtual_peer_ids[virtual_peer_id] ; dhinfo.status = RS_GXS_TUNNEL_DH_STATUS_UNINITIALIZED ; + dhinfo.own_gxs_id = own_gxs_id ; if(!locked_initDHSessionKey(dhinfo.dh)) { @@ -313,7 +315,7 @@ void p3GxsTunnelService::removeVirtualPeer(const TurtleFileHash& hash,const Turt DH_free(it->second.dh) ; _gxs_tunnel_virtual_peer_ids.erase(it) ; - std::map::iterator it2 = _gxs_tunnel_contacts.find(gxs_id) ; + std::map::iterator it2 = _gxs_tunnel_contacts.find(gxs_id) ; if(it2 == _gxs_tunnel_contacts.end()) { @@ -436,7 +438,7 @@ bool p3GxsTunnelService::handleEncryptedData(const uint8_t *data_bytes,uint32_t } RsGxsId gxs_id = it->second.gxs_id ; - std::map::iterator it2 = _gxs_tunnel_contacts.find(gxs_id) ; + std::map::iterator it2 = _gxs_tunnel_contacts.find(gxs_id) ; if(it2 == _gxs_tunnel_contacts.end()) { @@ -636,22 +638,25 @@ void p3GxsTunnelService::handleRecvDHPublicKey(RsGxsTunnelDHPublicKeyItem *item) #ifdef DEBUG_GXS_TUNNEL std::cerr << " DH key computation successed. New key in place." << std::endl; #endif - GxsTunnelPeerInfo& pinfo(_gxs_tunnel_contacts[senders_id]) ; + // make a hash of destination and source GXS ids in order to create the tunnel name + + RsGxsId own_id = it->second.own_gxs_id ; + RsGxsTunnelId tunnel_id = makeGxsTunnelId(own_id,senders_id) ; + + GxsTunnelPeerInfo& pinfo(_gxs_tunnel_contacts[tunnel_id]) ; // Now hash the key buffer into a 16 bytes key. assert(GXS_TUNNEL_AES_KEY_SIZE <= Sha1CheckSum::SIZE_IN_BYTES) ; memcpy(pinfo.aes_key, RsDirUtil::sha1sum(key_buff,size).toByteArray(),GXS_TUNNEL_AES_KEY_SIZE) ; delete[] key_buff ; - + pinfo.last_contact = time(NULL) ; pinfo.last_keep_alive_sent = time(NULL) ; pinfo.status = RS_GXS_TUNNEL_STATUS_CAN_TALK ; pinfo.virtual_peer_id = vpid ; pinfo.direction = it->second.direction ; - - if(pinfo.direction == RsTurtleGenericTunnelItem::DIRECTION_CLIENT) - pinfo.own_gxs_id = gxsIdFromHash(it->second.hash) ; + pinfo.own_gxs_id = own_id ; #ifdef DEBUG_GXS_TUNNEL std::cerr << " DH key computed. Tunnel is now secured!" << std::endl; @@ -676,6 +681,29 @@ void p3GxsTunnelService::handleRecvDHPublicKey(RsGxsTunnelDHPublicKeyItem *item) //RsServer::notify()->notifyListChange(NOTIFY_LIST_PRIVATE_INCOMING_CHAT, NOTIFY_TYPE_ADD); } +RsGxsTunnelId p3GxsTunnelService::makeGxsTunnelId(const RsGxsId& own_id,const RsGxsId& distant_id) const +{ + unsigned char mem[RsGxsId::SIZE_IN_BYTES * 2] ; + + // Always sort the ids, as a matter to avoid confusion between the two. Also that generates the same tunnel ID on both sides + // which helps debugging. If the code is right this is not needed anyway. + + if(own_id < distant_id) + { + memcpy(mem, own_id.toBytesArray(), RsGxsId::SIZE_IN_BYTES) ; + memcpy(mem+RsGxsId::SIZE_IN_BYTES, distant_id.toBytesArray(), RsGxsId::SIZE_IN_BYTES) ; + } + else + { + memcpy(mem, distant_id.toBytesArray(), RsGxsId::SIZE_IN_BYTES) ; + memcpy(mem+RsGxsId::SIZE_IN_BYTES, own_id.toBytesArray(), RsGxsId::SIZE_IN_BYTES) ; + } + + assert( RsGxsTunnelId::SIZE_IN_BYTES <= Sha1CheckSum::SIZE_IN_BYTES ) ; + + return RsGxsTunnelId( RsUtil::sha1sum(mem, 2*RsGxsId::SIZE_IN_BYTES).toByteArray() ) ; +} + bool p3GxsTunnelService::locked_sendDHPublicKey(const DH *dh,const RsGxsId& own_gxs_id,const RsPeerId& virtual_peer_id) { if(dh == NULL) @@ -847,7 +875,7 @@ void p3GxsTunnelService::sendEncryptedTurtleData(const uint8_t *buff,uint32_t rs #endif RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - std::map::iterator it = _gxs_tunnel_contacts.find(gxs_id) ; + std::map::iterator it = _gxs_tunnel_contacts.find(gxs_id) ; if(it == _gxs_tunnel_contacts.end()) { @@ -912,7 +940,7 @@ void p3GxsTunnelService::sendEncryptedTurtleData(const uint8_t *buff,uint32_t rs mTurtle->sendTurtleData(virtual_peer_id,gitem) ; } -bool p3GxsTunnelService::requestSecuredTunnel(const RsGxsId& to_gxs_id,const RsGxsId& from_gxs_id,RsGxsTunnelClientService *client,uint32_t& error_code) +bool p3GxsTunnelService::requestSecuredTunnel(const RsGxsId& to_gxs_id, const RsGxsId& from_gxs_id, RsGxsTunnelId &tunnel_id, uint32_t& error_code) { // should be a parameter. @@ -942,14 +970,17 @@ bool p3GxsTunnelService::requestSecuredTunnel(const RsGxsId& to_gxs_id,const RsG return true ; } -void p3GxsTunnelService::startClientGxsTunnelConnection(const RsGxsId& to_gxs_id,const RsGxsId& from_gxs_id) +void p3GxsTunnelService::startClientGxsTunnelConnection(const RsGxsId& to_gxs_id,const RsGxsId& from_gxs_id,RsGxsTunnelId& tunnel_id) { + RsGxsTunnelId tnl_id = makeGxsTunnelId(from_gxs_id,to_gxs_id) ; + tunnel_id = tnl_id ; + { RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - if(_gxs_tunnel_contacts.find(to_gxs_id) != _gxs_tunnel_contacts.end()) + if(_gxs_tunnel_contacts.find(tunnel_id) != _gxs_tunnel_contacts.end()) { - std::cerr << "GxsTunnelService:: asking distant chat connexion to a peer who's already in a chat. Ignoring." << std::endl; + std::cerr << "GxsTunnelService:: asking GXS tunnel for a configuration that already exits.Ignoring." << std::endl; return ; } } @@ -961,6 +992,7 @@ void p3GxsTunnelService::startClientGxsTunnelConnection(const RsGxsId& to_gxs_id info.last_keep_alive_sent = now ; info.status = RS_GXS_TUNNEL_STATUS_TUNNEL_DN ; info.own_gxs_id = from_gxs_id ; + info.to_gxs_id = to_gxs_id ; info.direction = RsTurtleGenericTunnelItem::DIRECTION_SERVER ; info.virtual_peer_id.clear(); @@ -968,11 +1000,13 @@ void p3GxsTunnelService::startClientGxsTunnelConnection(const RsGxsId& to_gxs_id { RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - _gxs_tunnel_contacts[to_gxs_id] = info ; + + _gxs_tunnel_contacts[tnt_id] = info ; } // Now ask the turtle router to manage a tunnel for that hash. +#warning need to make sure that we can ask the same hash if the from ID is different. What's going to happen?? RsFileHash hash = hashFromGxsId(to_gxs_id) ; #ifdef DEBUG_GXS_TUNNEL std::cerr << "Starting distant chat to " << to_gxs_id << ", hash = " << hash << ", from " << from_gxs_id << std::endl; @@ -1032,7 +1066,7 @@ bool p3GxsTunnelService::getTunnelStatus(const RsGxsId& gxs_id,uint32_t& status, { RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - std::map::const_iterator it = _gxs_tunnel_contacts.find(gxs_id) ; + std::map::const_iterator it = _gxs_tunnel_contacts.find(gxs_id) ; if(it != _gxs_tunnel_contacts.end()) { @@ -1049,7 +1083,7 @@ bool p3GxsTunnelService::getTunnelStatus(const RsGxsId& gxs_id,uint32_t& status, return false ; } -bool p3GxsTunnelService::closeExistingTunnel(const RsGxsId& gxs_id) +bool p3GxsTunnelService::closeExistingTunnel(const RsGxsTunnelId& tunnel_id) { // two cases: // - client needs to stop asking for tunnels => remove the hash from the list of tunnelled files @@ -1058,7 +1092,7 @@ bool p3GxsTunnelService::closeExistingTunnel(const RsGxsId& gxs_id) { RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - std::map::const_iterator it = _gxs_tunnel_contacts.find(gxs_id) ; + std::map::const_iterator it = _gxs_tunnel_contacts.find(gxs_id) ; if(it == _gxs_tunnel_contacts.end()) { diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.h b/libretroshare/src/gxstunnel/p3gxstunnel.h index a33c60862..a5efcfdc5 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.h +++ b/libretroshare/src/gxstunnel/p3gxstunnel.h @@ -51,6 +51,42 @@ // // Data is send to a service ID (could be any existing service ID). The endpoint of the tunnel must register each service, in order to // allow the data to be transmitted/sent from/to that service. Otherwise an error is issued. +// +// Algorithms +// +// Tunnel establishment +// * we need to layers: the turtle layer, and the GXS id layer. +// * at the turtle layer: +// - accept virtual peers from turtle tunnel service. The hash for that VP only depends on the server GXS id at server side, which is our +// own ID at server side, and destination ID at client side. What happens if two different clients request to talk to the same GXS id? (same hash) +// They should use different virtual peers, so it should be ok. +// - multiple tunnels may end up to the same hash, but will correspond to different GXS tunnels since the GXS id in the other side is different. +// +// * at the GXS layer +// - we should be able to have as many tunnels as they are different couples of GXS ids to interact. That means the tunnel should be determined +// by a mix between our own GXS id and the GXS id we're talking to. That is what the TunnelVirtualPeer is. +// + +// +// RequestTunnel(source_own_id,destination_id) +// | +// +---------------------------> p3Turtle::monitorTunnels( hash(destination_id) ) +// | +// [Turtle async work] -------------------+ +// | | +// handleTunnelRequest() <-----------------------------------------------+ | +// | | +// +---------------- keep record in _gxs_tunnel_virtual_peer_id, initiate DH exchange | +// | +// handleDHPublicKey() <-----------------------------------------------------------------------------+ +// | +// +---------------- update _gxs_tunnel_contacts[ tunnel_hash = hash(own_id, destination_id) ] +// | +// +---------------- notify client service that Peer(destination_id, tunnel_hash) is ready to talk to +// +// Notes +// * one other option would be to make the turtle hash depend on both GXS ids in a way that it is possible to find which are the two ids on the server side. +// but that would prevent the use of unknown IDs, which we would like to offer as well. #include #include @@ -74,9 +110,9 @@ public: // 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. // - virtual bool requestSecuredTunnel(const RsGxsId& to_id,const RsGxsId& from_id,RsGxsTunnelClientService *client,uint32_t& error_code) ; - virtual bool closeExistingTunnel(const RsGxsId& pid) ; - virtual bool getTunnelStatus(const RsGxsId &gxs_id,uint32_t &status, RsGxsId *from_gxs_id=NULL) ; + virtual bool requestSecuredTunnel(const RsGxsId& to_id,const RsGxsId& from_id,RsGxsTunnelId& tunnel_id,uint32_t& error_code) ; + virtual bool closeExistingTunnel(const RsGxsTunnelId &tunnel_id) ; + virtual bool getTunnelStatus(const RsGxsTunnelId& tunnel_id,uint32_t &status); private: void flush() ; @@ -108,6 +144,7 @@ private: DH *dh ; RsGxsId gxs_id ; + RsGxsId own_gxs_id ; RsTurtleGenericTunnelItem::Direction direction ; uint32_t status ; TurtleFileHash hash ; @@ -115,7 +152,7 @@ private: // This maps contains the current peers to talk to with distant chat. // - std::map _gxs_tunnel_contacts ; // current peers we can talk to + std::map _gxs_tunnel_contacts ; // current peers we can talk to std::map _gxs_tunnel_virtual_peer_ids ; // current virtual peers. Used to figure out tunnels, etc. // List of items to be sent asap. Used to store items that we cannot pass directly to @@ -133,7 +170,7 @@ private: // session handling handles void markGxsTunnelAsClosed(const RsGxsId &gxs_id) ; - void startClientGxsTunnelConnection(const RsGxsId &to_gxs_id, const RsGxsId& from_gxs_id) ; + void startClientGxsTunnelConnection(const RsGxsId &to_gxs_id, const RsGxsId& from_gxs_id, RsGxsTunnelId &tunnel_id) ; void locked_restartDHSession(const RsPeerId &virtual_peer_id, const RsGxsId &own_gxs_id) ; // utility functions @@ -148,6 +185,7 @@ private: bool locked_initDHSessionKey(DH *&dh); TurtleVirtualPeerId virtualPeerIdFromHash(const TurtleFileHash& hash) ; // ... and to a hash for p3turtle + RsGxsTunnelId makeGxsTunnelId(const RsGxsId &own_id, const RsGxsId &distant_id) const; // creates a unique ID from two GXS ids. // item handling diff --git a/libretroshare/src/retroshare/rsgxstunnel.h b/libretroshare/src/retroshare/rsgxstunnel.h index 3024b96d7..cd3498877 100644 --- a/libretroshare/src/retroshare/rsgxstunnel.h +++ b/libretroshare/src/retroshare/rsgxstunnel.h @@ -36,7 +36,7 @@ public: static const uint32_t RS_GXS_TUNNEL_ERROR_NO_ERROR = 0x0000 ; static const uint32_t RS_GXS_TUNNEL_ERROR_UNKNOWN_GXS_ID = 0x0001 ; - typedef TurtleVirtualPeerId RsGxsTunnelId ; + typedef GXSTunnelId RsGxsTunnelId ; class RsGxsTunnelClientService { @@ -44,12 +44,12 @@ public: // The client should derive this in order to handle notifications from the tunnel service. // This cannot be ignored because the client needs to know when the tunnel is active. - virtual void notifyTunnelStatus(const RsGxsId& id,uint32_t tunnel_status) =0; + virtual void notifyTunnelStatus(const RsGxsTunnelId& tunnel_id,uint32_t tunnel_status) =0; // Data obtained from the corresponding GXS id. The memory ownership is transferred to the client, which // is responsible to free it using free() once used. - virtual void receiveData(const RsGxsId& id,unsigned char *data,uint32_t data_size) =0; + virtual void receiveData(const RsGxsTunnelId& id,const RsGxsId& from_id,unsigned char *data,uint32_t data_size) =0; }; class GxsTunnelInfo @@ -88,7 +88,7 @@ public: // When the tunnel is secured, the client---here supplied as argument---will be notified. He can // then send data into the tunnel. The same tunnel may be used by different clients. - virtual bool requestSecuredTunnel(const RsGxsId& to_id,const RsGxsId& from_id,uint32_t& error_code) =0 ; + virtual bool requestSecuredTunnel(const RsGxsId& to_id,const RsGxsId& from_id,RsGxsTunnelId& tunnel_id,uint32_t& error_code) =0 ; // Data is sent through the established tunnel, possibly multiple times, until reception is acknowledged. If the tunnel does not exist, the item is rejected and // an error is issued. In any case, the memory ownership of the data is transferred to the tunnel service, so the client should not use it afterwards. diff --git a/libretroshare/src/retroshare/rsids.h b/libretroshare/src/retroshare/rsids.h index 5b1a60bfa..6893e8c11 100644 --- a/libretroshare/src/retroshare/rsids.h +++ b/libretroshare/src/retroshare/rsids.h @@ -218,6 +218,7 @@ static const uint32_t RS_GENERIC_ID_GXS_ID_TYPE = 0x0006 ; static const uint32_t RS_GENERIC_ID_GXS_MSG_ID_TYPE = 0x0007 ; static const uint32_t RS_GENERIC_ID_GXS_CIRCLE_ID_TYPE = 0x0008 ; static const uint32_t RS_GENERIC_ID_GROUTER_ID_TYPE = 0x0009 ; +static const uint32_t RS_GENERIC_ID_GXS_TUNNEL_ID_TYPE = 0x0010 ; typedef t_RsGenericIdType< SSL_ID_SIZE , false, RS_GENERIC_ID_SSL_ID_TYPE> SSLIdType ; typedef t_RsGenericIdType< PGP_KEY_ID_SIZE , true, RS_GENERIC_ID_PGP_ID_TYPE> PGPIdType ; @@ -227,4 +228,5 @@ typedef t_RsGenericIdType< PGP_KEY_FINGERPRINT_SIZE, true, RS_GENERIC_ID_PGP_F typedef t_RsGenericIdType< CERT_SIGN_LEN , false, RS_GENERIC_ID_GXS_GROUP_ID_TYPE > GXSGroupId ; typedef t_RsGenericIdType< CERT_SIGN_LEN , false, RS_GENERIC_ID_GXS_ID_TYPE > GXSId ; typedef t_RsGenericIdType< CERT_SIGN_LEN , false, RS_GENERIC_ID_GXS_CIRCLE_ID_TYPE > GXSCircleId ; +typedef t_RsGenericIdType< SSL_ID_SIZE , false, RS_GENERIC_ID_GXS_TUNNEL_ID_TYPE > GXSTunnelId ; From 85a9e4cbae7bda1af9950bfd0aa32f33eaec17bc Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 23 Nov 2015 22:19:18 -0500 Subject: [PATCH 06/26] coding phase done. Needs testing/debugging --- libretroshare/src/gxstunnel/p3gxstunnel.cc | 224 ++++++++++++--------- libretroshare/src/gxstunnel/p3gxstunnel.h | 34 +++- 2 files changed, 158 insertions(+), 100 deletions(-) diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.cc b/libretroshare/src/gxstunnel/p3gxstunnel.cc index a619e9460..44511500e 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.cc +++ b/libretroshare/src/gxstunnel/p3gxstunnel.cc @@ -98,7 +98,8 @@ void p3GxsTunnelService::flush() { std::cerr << "(II) GxsTunnelService:: forcing new tunnel campain." << std::endl; - mTurtle->forceReDiggTunnels( hashFromGxsId(it->first) ); +#warning make sure we can use random here. + mTurtle->forceReDiggTunnels( randomHashFromDestinationGxsId(it->second.to_gxs_id) ); } } if(it->second.last_keep_alive_sent + GXS_TUNNEL_KEEP_ALIVE_TIMEOUT < now && it->second.status == RS_GXS_TUNNEL_STATUS_CAN_TALK) @@ -106,7 +107,7 @@ void p3GxsTunnelService::flush() RsGxsTunnelStatusItem *cs = new RsGxsTunnelStatusItem ; cs->flags = RS_GXS_TUNNEL_FLAG_KEEP_ALIVE; - cs->PeerId(RsPeerId(it->first)) ; + cs->PeerId(it->second.virtual_peer_id) ; // we send off-mutex to avoid deadlock. @@ -170,7 +171,25 @@ bool p3GxsTunnelService::handleIncomingItem(RsGxsTunnelItem *item) void p3GxsTunnelService::handleRecvStatusItem(RsGxsTunnelStatusItem *cs) { if(cs->flags & RS_GXS_TUNNEL_FLAG_CLOSING_DISTANT_CONNECTION) - markGxsTunnelAsClosed(RsGxsId(cs->PeerId())) ; + { + RsGxsTunnelId tunnel_id ; + TurtleVirtualPeerId vpid = cs->PeerId() ; + + { + RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + + std::map::iterator it = _gxs_tunnel_virtual_peer_ids.find(vpid) ; + + if(it == _gxs_tunnel_virtual_peer_ids.end()) + { + std::cerr << " (EE) Cannot find hash in gxs_tunnel peer list!!" << std::endl; + return ; + } + tunnel_id = it->second.tunnel_id ; + } + + markGxsTunnelAsClosed(tunnel_id); + } // nothing more to do, because the decryption routing will update the last_contact time when decrypting. @@ -187,18 +206,21 @@ bool p3GxsTunnelService::handleTunnelRequest(const RsFileHash& hash,const RsPeer std::list own_id_list ; rsIdentity->getOwnIds(own_id_list) ; - // re-computing the hash from the GXS id allows to dynamically change the hash. That will allow - // the use of a contact passphrase, if needed. + // extract the GXS id from the hash + + RsGxsId destination_id = destinationGxsIdFromHash(hash) ; + + // linear search. Not costly because we have typically a low number of IDs. Otherwise, this really should be avoided! for(std::list::const_iterator it(own_id_list.begin());it!=own_id_list.end();++it) - if(hashFromGxsId(*it) == hash) + if(*it == destination_id) { #ifdef DEBUG_GXS_TUNNEL std::cerr << "GxsTunnelService::handleTunnelRequest: received tunnel request for hash " << hash << std::endl; std::cerr << " answering true!" << std::endl; #endif return true ; - } + } return false ; } @@ -223,17 +245,19 @@ void p3GxsTunnelService::addVirtualPeer(const TurtleFileHash& hash,const TurtleV dhinfo.direction = dir ; dhinfo.hash = hash ; dhinfo.status = RS_GXS_TUNNEL_DH_STATUS_UNINITIALIZED ; + dhinfo.tunnel_id.clear(); - if(dir == RsTurtleGenericTunnelItem::DIRECTION_CLIENT) + if(dir == RsTurtleGenericTunnelItem::DIRECTION_CLIENT) // server side { // check that a tunnel is not already working for this hash. If so, give up. - own_gxs_id = gxsIdFromHash(hash) ; + own_gxs_id = destinationGxsIdFromHash(hash) ; } else // client side { - RsGxsId to_gxs_id = gxsIdFromHash(hash) ; - std::map::const_iterator it = _gxs_tunnel_contacts.find(to_gxs_id) ; + std::map::const_iterator it ; + + while(it != _gxs_tunnel_contacts.end() && it->second.hash != hash) ++it ; if(it == _gxs_tunnel_contacts.end()) { @@ -271,7 +295,7 @@ void p3GxsTunnelService::locked_restartDHSession(const RsPeerId& virtual_peer_id #ifdef DEBUG_GXS_TUNNEL std::cerr << "Starting new DH session." << std::endl; #endif - GxsTunnelDHInfo& dhinfo = _gxs_tunnel_virtual_peer_ids[virtual_peer_id] ; + GxsTunnelDHInfo& dhinfo = _gxs_tunnel_virtual_peer_ids[virtual_peer_id] ; // creates it, if necessary dhinfo.status = RS_GXS_TUNNEL_DH_STATUS_UNINITIALIZED ; dhinfo.own_gxs_id = own_gxs_id ; @@ -301,7 +325,7 @@ void p3GxsTunnelService::removeVirtualPeer(const TurtleFileHash& hash,const Turt RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ RsGxsId gxs_id ; - std::map::iterator it = _gxs_tunnel_virtual_peer_ids.find(virtual_peer_id) ; + std::map::iterator it = _gxs_tunnel_virtual_peer_ids.find(virtual_peer_id) ; if(it == _gxs_tunnel_virtual_peer_ids.end()) { @@ -309,17 +333,18 @@ void p3GxsTunnelService::removeVirtualPeer(const TurtleFileHash& hash,const Turt return ; } - gxs_id = it->second.gxs_id ; + RsGxsTunnelId tunnel_id = it->second.tunnel_id ; if(it->second.dh != NULL) DH_free(it->second.dh) ; + _gxs_tunnel_virtual_peer_ids.erase(it) ; - std::map::iterator it2 = _gxs_tunnel_contacts.find(gxs_id) ; + std::map::iterator it2 = _gxs_tunnel_contacts.find(tunnel_id) ; if(it2 == _gxs_tunnel_contacts.end()) { - std::cerr << "(EE) Cannot find GXS id " << gxs_id << " in contact list. Weird." << std::endl; + std::cerr << "(EE) Cannot find tunnel id " << tunnel_id << " in contact list. Weird." << std::endl; return ; } if(it2->second.virtual_peer_id == virtual_peer_id) @@ -429,7 +454,7 @@ bool p3GxsTunnelService::handleEncryptedData(const uint8_t *data_bytes,uint32_t uint8_t *decrypted_data = new uint8_t[decrypted_size]; uint8_t aes_key[GXS_TUNNEL_AES_KEY_SIZE] ; - std::map::iterator it = _gxs_tunnel_virtual_peer_ids.find(virtual_peer_id) ; + std::map::iterator it = _gxs_tunnel_virtual_peer_ids.find(virtual_peer_id) ; if(it == _gxs_tunnel_virtual_peer_ids.end()) { @@ -437,12 +462,12 @@ bool p3GxsTunnelService::handleEncryptedData(const uint8_t *data_bytes,uint32_t return true ; } - RsGxsId gxs_id = it->second.gxs_id ; - std::map::iterator it2 = _gxs_tunnel_contacts.find(gxs_id) ; + RsGxsTunnelId tunnel_id = it->second.tunnel_id ; + std::map::iterator it2 = _gxs_tunnel_contacts.find(tunnel_id) ; if(it2 == _gxs_tunnel_contacts.end()) { - std::cerr << "(EE) no GXS id data for ID=" << gxs_id << ". This is a bug." << std::endl; + std::cerr << "(EE) no tunnel data for tunnel ID=" << tunnel_id << ". This is a bug." << std::endl; return true ; } memcpy(aes_key,it2->second.aes_key,GXS_TUNNEL_AES_KEY_SIZE) ; @@ -503,7 +528,7 @@ bool p3GxsTunnelService::handleEncryptedData(const uint8_t *data_bytes,uint32_t // DH key items are sent even before we know who we speak to, so the virtual peer id is used in this // case only. - citem->PeerId(RsPeerId(gxs_id)) ; + citem->PeerId(virtual_peer_id) ; } #ifdef DEBUG_GXS_TUNNEL @@ -616,11 +641,16 @@ void p3GxsTunnelService::handleRecvDHPublicKey(RsGxsTunnelDHPublicKeyItem *item) std::cerr << " DH Session already set for this tunnel. Re-initing a new session!" << std::endl; #endif - locked_restartDHSession(vpid,_gxs_tunnel_contacts[senders_id].own_gxs_id) ; + locked_restartDHSession(vpid,it->second.own_gxs_id) ; } // gets current key params. By default, should contain all null pointers. // + RsGxsId own_id = it->second.own_gxs_id ; + + RsGxsTunnelId tunnel_id = makeGxsTunnelId(own_id,senders_id) ; + + it->second.tunnel_id = tunnel_id ; it->second.gxs_id = senders_id ; // Looks for the DH params. If not there yet, create them. @@ -640,9 +670,6 @@ void p3GxsTunnelService::handleRecvDHPublicKey(RsGxsTunnelDHPublicKeyItem *item) #endif // make a hash of destination and source GXS ids in order to create the tunnel name - RsGxsId own_id = it->second.own_gxs_id ; - RsGxsTunnelId tunnel_id = makeGxsTunnelId(own_id,senders_id) ; - GxsTunnelPeerInfo& pinfo(_gxs_tunnel_contacts[tunnel_id]) ; // Now hash the key buffer into a 16 bytes key. @@ -657,6 +684,8 @@ void p3GxsTunnelService::handleRecvDHPublicKey(RsGxsTunnelDHPublicKeyItem *item) pinfo.virtual_peer_id = vpid ; pinfo.direction = it->second.direction ; pinfo.own_gxs_id = own_id ; + + // note: the hash might still be nn initialised on server side. #ifdef DEBUG_GXS_TUNNEL std::cerr << " DH key computed. Tunnel is now secured!" << std::endl; @@ -673,15 +702,16 @@ void p3GxsTunnelService::handleRecvDHPublicKey(RsGxsTunnelDHPublicKeyItem *item) RsGxsTunnelStatusItem *cs = new RsGxsTunnelStatusItem ; cs->flags = RS_GXS_TUNNEL_FLAG_ACK_DISTANT_CONNECTION; - cs->PeerId(RsPeerId(senders_id)); + cs->PeerId(vpid) ; pendingGxsTunnelItems.push_back(cs) ; #warning should notify client here + //RsServer::notify()->notifyListChange(NOTIFY_LIST_PRIVATE_INCOMING_CHAT, NOTIFY_TYPE_ADD); } -RsGxsTunnelId p3GxsTunnelService::makeGxsTunnelId(const RsGxsId& own_id,const RsGxsId& distant_id) const +RsGxsTunnelId p3GxsTunnelService::makeGxsTunnelId(const RsGxsId &own_id, const RsGxsId &distant_id) const // creates a unique ID from two GXS ids. { unsigned char mem[RsGxsId::SIZE_IN_BYTES * 2] ; @@ -753,7 +783,7 @@ bool p3GxsTunnelService::locked_sendDHPublicKey(const DH *dh,const RsGxsId& own_ dhitem->signature = signature ; dhitem->gxs_key = signature_key_public ; - dhitem->PeerId(RsPeerId(virtual_peer_id)) ; // special case for DH items + dhitem->PeerId(virtual_peer_id) ; #ifdef DEBUG_GXS_TUNNEL std::cerr << " Pushing DH session key item to pending distant messages..." << std::endl; @@ -858,33 +888,40 @@ void p3GxsTunnelService::sendTurtleData(RsGxsTunnelItem *item) return ; } - sendEncryptedTurtleData(buff,rssize,RsGxsId(item->PeerId())) ; + sendEncryptedTurtleData(buff,rssize,item->PeerId()) ; free(buff) ; } delete item ; } -void p3GxsTunnelService::sendEncryptedTurtleData(const uint8_t *buff,uint32_t rssize,const RsGxsId& gxs_id) +void p3GxsTunnelService::sendEncryptedTurtleData(const uint8_t *buff,uint32_t rssize,const TurtleVirtualPeerId& vpid) { uint8_t aes_key[GXS_TUNNEL_AES_KEY_SIZE] ; uint64_t IV = 0; #ifdef DEBUG_GXS_TUNNEL - std::cerr << "Sending encrypted data to virtual gxs id " << gxs_id << std::endl; + std::cerr << "Sending encrypted data to tunnel wuth vpid " << vpid << std::endl; #endif RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - std::map::iterator it = _gxs_tunnel_contacts.find(gxs_id) ; + std::map::const_iterator it2 = _gxs_tunnel_virtual_peer_ids.find(vpid) ; + if(it2 == _gxs_tunnel_virtual_peer_ids.end()) + { + std::cerr << "(EE) no virtual peer " << vpid << ". Something's wrong!" << std::endl; + return ; + } + + std::map::iterator it = _gxs_tunnel_contacts.find(it2->second.tunnel_id) ; if(it == _gxs_tunnel_contacts.end()) { - std::cerr << "(EE) Cannot find contact key info for ID " << gxs_id << ". Cannot send message!" << std::endl; + std::cerr << "(EE) Cannot find contact key info for virtual peer id " << vpid << ". Cannot send message!" << std::endl; return ; } if(it->second.status != RS_GXS_TUNNEL_STATUS_CAN_TALK) { - std::cerr << "(EE) Cannot talk to " << gxs_id << ". Tunnel status is: " << it->second.status << std::endl; + std::cerr << "(EE) Cannot talk to vpid " << vpid << ". Tunnel status is: " << it->second.status << std::endl; return ; } @@ -963,7 +1000,7 @@ bool p3GxsTunnelService::requestSecuredTunnel(const RsGxsId& to_gxs_id, const Rs } RsGxsId own_gxs_id = from_gxs_id ; - startClientGxsTunnelConnection(to_gxs_id,own_gxs_id) ; + startClientGxsTunnelConnection(to_gxs_id,own_gxs_id,tunnel_id) ; error_code = RS_GXS_TUNNEL_ERROR_NO_ERROR ; @@ -972,6 +1009,10 @@ bool p3GxsTunnelService::requestSecuredTunnel(const RsGxsId& to_gxs_id, const Rs void p3GxsTunnelService::startClientGxsTunnelConnection(const RsGxsId& to_gxs_id,const RsGxsId& from_gxs_id,RsGxsTunnelId& tunnel_id) { + // compute a random hash for that pair, and init the DH session for it so that we can recognise it when we get the virtual peer for it. + + RsFileHash hash = randomHashFromDestinationGxsId(to_gxs_id) ; + RsGxsTunnelId tnl_id = makeGxsTunnelId(from_gxs_id,to_gxs_id) ; tunnel_id = tnl_id ; @@ -984,6 +1025,7 @@ void p3GxsTunnelService::startClientGxsTunnelConnection(const RsGxsId& to_gxs_id return ; } } + GxsTunnelPeerInfo info ; time_t now = time(NULL) ; @@ -993,6 +1035,7 @@ void p3GxsTunnelService::startClientGxsTunnelConnection(const RsGxsId& to_gxs_id info.status = RS_GXS_TUNNEL_STATUS_TUNNEL_DN ; info.own_gxs_id = from_gxs_id ; info.to_gxs_id = to_gxs_id ; + info.hash = hash ; info.direction = RsTurtleGenericTunnelItem::DIRECTION_SERVER ; info.virtual_peer_id.clear(); @@ -1001,18 +1044,16 @@ void p3GxsTunnelService::startClientGxsTunnelConnection(const RsGxsId& to_gxs_id { RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - _gxs_tunnel_contacts[tnt_id] = info ; + _gxs_tunnel_contacts[tunnel_id] = info ; } - // Now ask the turtle router to manage a tunnel for that hash. - -#warning need to make sure that we can ask the same hash if the from ID is different. What's going to happen?? - RsFileHash hash = hashFromGxsId(to_gxs_id) ; #ifdef DEBUG_GXS_TUNNEL std::cerr << "Starting distant chat to " << to_gxs_id << ", hash = " << hash << ", from " << from_gxs_id << std::endl; std::cerr << "Asking turtle router to monitor tunnels for hash " << hash << std::endl; #endif + // Now ask the turtle router to manage a tunnel for that hash. + mTurtle->monitorTunnels(hash,this,false) ; #warning check that this code should go. @@ -1026,7 +1067,7 @@ void p3GxsTunnelService::startClientGxsTunnelConnection(const RsGxsId& to_gxs_id #endif } -TurtleFileHash p3GxsTunnelService::hashFromGxsId(const RsGxsId& destination) +TurtleFileHash p3GxsTunnelService::randomHashFromDestinationGxsId(const RsGxsId& destination) { // This is in prevision for the "secured GXS tunnel" service, which will need a service ID to register, // just like GRouter does. @@ -1038,10 +1079,8 @@ TurtleFileHash p3GxsTunnelService::hashFromGxsId(const RsGxsId& destination) uint8_t bytes[20] ; memcpy(bytes,destination.toByteArray(),16) ; - bytes[16] = 0 ; - bytes[17] = 0 ; - bytes[18] = (client >> 8) & 0xff ; - bytes[19] = client & 0xff ; + + RAND_bytes(&bytes[16],4) ; // fill the last bytes with random crap. Very important to allow tunnels from different sources and statistically avoid collisions. // We could rehash this, with a secret key to get a HMAC. That would allow to publish secret distant chat // passphrases. I'll do this later if needed. @@ -1049,32 +1088,24 @@ TurtleFileHash p3GxsTunnelService::hashFromGxsId(const RsGxsId& destination) return Sha1CheckSum(bytes) ; } -RsGxsId p3GxsTunnelService::gxsIdFromHash(const TurtleFileHash& sum) +RsGxsId p3GxsTunnelService::destinationGxsIdFromHash(const TurtleFileHash& sum) { assert( RsGxsId::SIZE_IN_BYTES == 16) ; assert(Sha1CheckSum::SIZE_IN_BYTES == 20) ; - uint32_t client_id = sum.toByteArray()[19] + (sum.toByteArray()[18] << 8) ; - - if(client_id != RS_SERVICE_TYPE_GXS_TUNNEL) - std::cerr << "WARNING: GxsTunnelService::gxsIdFromHash(). Hash is not a distant file hash. This should not happen." << std::endl; - return RsGxsId(sum.toByteArray());// takes the first 16 bytes } -bool p3GxsTunnelService::getTunnelStatus(const RsGxsId& gxs_id,uint32_t& status, RsGxsId *from_gxs_id) +bool p3GxsTunnelService::getTunnelStatus(const RsGxsTunnelId& tunnel_id,uint32_t& status) { RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - std::map::const_iterator it = _gxs_tunnel_contacts.find(gxs_id) ; + std::map::const_iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; if(it != _gxs_tunnel_contacts.end()) { status = it->second.status ; - if(from_gxs_id != NULL) - *from_gxs_id = it->second.own_gxs_id ; - return true ; } @@ -1090,73 +1121,80 @@ bool p3GxsTunnelService::closeExistingTunnel(const RsGxsTunnelId& tunnel_id) // - server needs to only close the window and let the tunnel die. But the window should only open // if a message arrives. - { - RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - std::map::const_iterator it = _gxs_tunnel_contacts.find(gxs_id) ; + TurtleFileHash hash ; + TurtleVirtualPeerId vpid ; + { + RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + std::map::const_iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; - if(it == _gxs_tunnel_contacts.end()) - { - std::cerr << "(EE) Cannot close distant tunnel connection. No connection openned for gxs id " << gxs_id << std::endl; + if(it == _gxs_tunnel_contacts.end()) + { + std::cerr << "(EE) Cannot close distant tunnel connection. No connection openned for tunnel id " << tunnel_id << std::endl; - // We don't know if we are server or client side, but mTurtle will not complain if the hash doesn't exist. + // We cannot stop tunnels, since their peer id is lost. Anyway, they'll die of starving. - mTurtle->stopMonitoringTunnels( hashFromGxsId(gxs_id) ); + return false ; + } + vpid = it->second.virtual_peer_id ; - return false ; - } - if(it->second.direction == RsTurtleGenericTunnelItem::DIRECTION_CLIENT) // nothing more to do for server side. - return true ; - } + if(it->second.direction == RsTurtleGenericTunnelItem::DIRECTION_CLIENT) // nothing more to do for server side. + return true ; - // send a status item saying that we're closing the connection + std::map::const_iterator it2 = _gxs_tunnel_virtual_peer_ids.find(vpid) ; + + if(it2 != _gxs_tunnel_virtual_peer_ids.end()) + hash = it2->second.hash ; + } + + // send a status item saying that we're closing the connection #ifdef DEBUG_GXS_TUNNEL - std::cerr << " Sending a ACK to close the tunnel since we're managing it. Peer id=." << gxs_id << std::endl; + std::cerr << " Sending a ACK to close the tunnel since we're managing it. tunnel id=." << tunnel_id << std::endl; #endif - RsGxsTunnelStatusItem *cs = new RsGxsTunnelStatusItem ; + RsGxsTunnelStatusItem *cs = new RsGxsTunnelStatusItem ; - cs->flags = RS_GXS_TUNNEL_FLAG_CLOSING_DISTANT_CONNECTION; - cs->PeerId(RsPeerId(gxs_id)); + cs->flags = RS_GXS_TUNNEL_FLAG_CLOSING_DISTANT_CONNECTION; + cs->PeerId(vpid) ; - sendTurtleData(cs) ; // that needs to be done off-mutex and before we close the tunnel. + sendTurtleData(cs) ; // that needs to be done off-mutex and before we close the tunnel. #ifdef DEBUG_GXS_TUNNEL - std::cerr << " This is client side. Stopping tunnel manageement for gxs_id " << gxs_id << std::endl; + std::cerr << " This is client side. Stopping tunnel manageement for tunnel_id " << tunnel_id << std::endl; #endif - mTurtle->stopMonitoringTunnels( hashFromGxsId(gxs_id) ); - { - RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - std::map::iterator it = _gxs_tunnel_contacts.find(gxs_id) ; + mTurtle->stopMonitoringTunnels( hash ) ; // still valid if the hash is null + { + RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + std::map::iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; - if(it == _gxs_tunnel_contacts.end()) // server side. Nothing to do. - { - std::cerr << "(EE) Cannot close chat associated to GXS id " << gxs_id << ": not found." << std::endl; - return false ; - } + if(it == _gxs_tunnel_contacts.end()) // server side. Nothing to do. + { + std::cerr << "(EE) Cannot close chat associated to tunnel id " << tunnel_id << ": not found." << std::endl; + return false ; + } - _gxs_tunnel_contacts.erase(it) ; + _gxs_tunnel_contacts.erase(it) ; - // GxsTunnelService::removeVirtualPeerId() will be called by the turtle service. - } - return true ; + // GxsTunnelService::removeVirtualPeerId() will be called by the turtle service. + } + return true ; } -void p3GxsTunnelService::markGxsTunnelAsClosed(const RsGxsId& gxs_id) +void p3GxsTunnelService::markGxsTunnelAsClosed(const RsGxsTunnelId& tunnel_id) { RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - std::map::iterator it = _gxs_tunnel_contacts.find(gxs_id) ; + std::map::iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; if(it == _gxs_tunnel_contacts.end()) { - std::cerr << "(EE) Cannot mark distant chat connection as closed. No connection openned for gxs id " << gxs_id << ". Unexpected situation." << std::endl; + std::cerr << "(EE) Cannot mark distant chat connection as closed. No connection openned for tunnel id " << tunnel_id << ". Unexpected situation." << std::endl; return ; } if(it->second.direction == RsTurtleGenericDataItem::DIRECTION_CLIENT) { #ifdef DEBUG_GXS_TUNNEL - std::cerr << " This is server side. Marking distant chat as remotely closed for GXS id " << gxs_id << std::endl; + std::cerr << " This is server side. Marking distant chat as remotely closed for tunnel id " << tunnel_id << std::endl; #endif it->second.status = RS_GXS_TUNNEL_STATUS_REMOTELY_CLOSED ; } diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.h b/libretroshare/src/gxstunnel/p3gxstunnel.h index a5efcfdc5..ee7ec62cf 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.h +++ b/libretroshare/src/gxstunnel/p3gxstunnel.h @@ -55,13 +55,25 @@ // Algorithms // // Tunnel establishment -// * we need to layers: the turtle layer, and the GXS id layer. +// * we need two layers: the turtle layer, and the GXS id layer. // * at the turtle layer: // - accept virtual peers from turtle tunnel service. The hash for that VP only depends on the server GXS id at server side, which is our // own ID at server side, and destination ID at client side. What happens if two different clients request to talk to the same GXS id? (same hash) // They should use different virtual peers, so it should be ok. // - multiple tunnels may end up to the same hash, but will correspond to different GXS tunnels since the GXS id in the other side is different. // +// Turtle hash: [ 0 ---------------15 16---19 ] +// Destination Source +// +// We Use 16 bytes to target the exact destination of the hash. The source part is just 4 arbitrary bytes that need to be different for all source +// IDs that come from the same peer, which is quite likely to be sufficient. The real source of the tunnel will make itself known when sending the +// DH key. +// +// Another option is to use random bytes in 16-19. But then, we would digg multiple times different tunnels between the same two peers even when requesting +// a GXS tunnel for the same pair of GXS ids. Is that a problem? +// - that solves the problem of colliding source GXS ids (since 4 bytes is too small) +// - the DH will make it clear that we're talking to the same person if it already exist. +// // * at the GXS layer // - we should be able to have as many tunnels as they are different couples of GXS ids to interact. That means the tunnel should be determined // by a mix between our own GXS id and the GXS id we're talking to. That is what the TunnelVirtualPeer is. @@ -87,6 +99,11 @@ // Notes // * one other option would be to make the turtle hash depend on both GXS ids in a way that it is possible to find which are the two ids on the server side. // but that would prevent the use of unknown IDs, which we would like to offer as well. +// Without this, it's not possible to request two tunnels to a same server GXS id but from a different client GXS id. Indeed, if the two hashes are the same, +// from the same peer, the tunnel names will be identical and so will be the virtual peer ids, if the route is the same (because of multi-tunneling, they +// will be different if the route is different). +// +// * #include #include @@ -133,8 +150,10 @@ private: uint32_t status ; // info: do we have a tunnel ? RsPeerId virtual_peer_id; // given by the turtle router. Identifies the tunnel. + RsGxsId to_gxs_id; // gxs id we're talking to RsGxsId own_gxs_id ; // gxs id we're using to talk. RsTurtleGenericTunnelItem::Direction direction ; // specifiec wether we are client(managing the tunnel) or server. + TurtleFileHash hash ; // hash that is last used. This is necessary for handling tunnel establishment }; class GxsTunnelDHInfo @@ -145,6 +164,7 @@ private: DH *dh ; RsGxsId gxs_id ; RsGxsId own_gxs_id ; + RsGxsTunnelId tunnel_id ; // this is a proxy, since we cna always recompute that from the two previous values. RsTurtleGenericTunnelItem::Direction direction ; uint32_t status ; TurtleFileHash hash ; @@ -152,8 +172,8 @@ private: // This maps contains the current peers to talk to with distant chat. // - std::map _gxs_tunnel_contacts ; // current peers we can talk to - std::map _gxs_tunnel_virtual_peer_ids ; // current virtual peers. Used to figure out tunnels, etc. + std::map _gxs_tunnel_contacts ; // current peers we can talk to + std::map _gxs_tunnel_virtual_peer_ids ; // current virtual peers. Used to figure out tunnels, etc. // List of items to be sent asap. Used to store items that we cannot pass directly to // sendTurtleData(), because of Mutex protection. @@ -169,14 +189,14 @@ private: // session handling handles - void markGxsTunnelAsClosed(const RsGxsId &gxs_id) ; + void markGxsTunnelAsClosed(const RsGxsTunnelId &tunnel_id) ; void startClientGxsTunnelConnection(const RsGxsId &to_gxs_id, const RsGxsId& from_gxs_id, RsGxsTunnelId &tunnel_id) ; void locked_restartDHSession(const RsPeerId &virtual_peer_id, const RsGxsId &own_gxs_id) ; // utility functions - static TurtleFileHash hashFromGxsId(const RsGxsId& destination) ; - static RsGxsId gxsIdFromHash(const TurtleFileHash& sum) ; + static TurtleFileHash randomHashFromDestinationGxsId(const RsGxsId& destination) ; + static RsGxsId destinationGxsIdFromHash(const TurtleFileHash& sum) ; // Cryptography management @@ -194,7 +214,7 @@ private: // Comunication with Turtle service void sendTurtleData(RsGxsTunnelItem *) ; - void sendEncryptedTurtleData(const uint8_t *buff,uint32_t rssize,const RsGxsId &gxs_id) ; + void sendEncryptedTurtleData(const uint8_t *buff, uint32_t rssize, const TurtleVirtualPeerId &vpid) ; bool handleEncryptedData(const uint8_t *data_bytes,uint32_t data_size,const TurtleFileHash& hash,const RsPeerId& virtual_peer_id) ; static TurtleFileHash hashFromVirtualPeerId(const DistantChatPeerId& peerId) ; // converts IDs so that we can talk to RsPeerId from outside From 19f1a82bd8494b336f0e7d6196a769964ff01833 Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 23 Nov 2015 22:31:31 -0500 Subject: [PATCH 07/26] fixed compilation --- libretroshare/src/gxstunnel/p3gxstunnel.cc | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.cc b/libretroshare/src/gxstunnel/p3gxstunnel.cc index 44511500e..3ebe11870 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.cc +++ b/libretroshare/src/gxstunnel/p3gxstunnel.cc @@ -711,7 +711,9 @@ void p3GxsTunnelService::handleRecvDHPublicKey(RsGxsTunnelDHPublicKeyItem *item) //RsServer::notify()->notifyListChange(NOTIFY_LIST_PRIVATE_INCOMING_CHAT, NOTIFY_TYPE_ADD); } -RsGxsTunnelId p3GxsTunnelService::makeGxsTunnelId(const RsGxsId &own_id, const RsGxsId &distant_id) const // creates a unique ID from two GXS ids. +// Note: for some obscure reason, the typedef does not work here. Looks like a compiler error. So I use the primary type. + +GXSTunnelId p3GxsTunnelService::makeGxsTunnelId(const RsGxsId &own_id, const RsGxsId &distant_id) const // creates a unique ID from two GXS ids. { unsigned char mem[RsGxsId::SIZE_IN_BYTES * 2] ; @@ -720,18 +722,18 @@ RsGxsTunnelId p3GxsTunnelService::makeGxsTunnelId(const RsGxsId &own_id, const R if(own_id < distant_id) { - memcpy(mem, own_id.toBytesArray(), RsGxsId::SIZE_IN_BYTES) ; - memcpy(mem+RsGxsId::SIZE_IN_BYTES, distant_id.toBytesArray(), RsGxsId::SIZE_IN_BYTES) ; + memcpy(mem, own_id.toByteArray(), RsGxsId::SIZE_IN_BYTES) ; + memcpy(mem+RsGxsId::SIZE_IN_BYTES, distant_id.toByteArray(), RsGxsId::SIZE_IN_BYTES) ; } else { - memcpy(mem, distant_id.toBytesArray(), RsGxsId::SIZE_IN_BYTES) ; - memcpy(mem+RsGxsId::SIZE_IN_BYTES, own_id.toBytesArray(), RsGxsId::SIZE_IN_BYTES) ; + memcpy(mem, distant_id.toByteArray(), RsGxsId::SIZE_IN_BYTES) ; + memcpy(mem+RsGxsId::SIZE_IN_BYTES, own_id.toByteArray(), RsGxsId::SIZE_IN_BYTES) ; } assert( RsGxsTunnelId::SIZE_IN_BYTES <= Sha1CheckSum::SIZE_IN_BYTES ) ; - return RsGxsTunnelId( RsUtil::sha1sum(mem, 2*RsGxsId::SIZE_IN_BYTES).toByteArray() ) ; + return RsGxsTunnelId( RsDirUtil::sha1sum(mem, 2*RsGxsId::SIZE_IN_BYTES).toByteArray() ) ; } bool p3GxsTunnelService::locked_sendDHPublicKey(const DH *dh,const RsGxsId& own_gxs_id,const RsPeerId& virtual_peer_id) From b552408aab726ad29dfa54168f7bbdef63f24864 Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 24 Nov 2015 21:57:59 -0500 Subject: [PATCH 08/26] added service part and item queues to GXS tunnel service --- libretroshare/src/gxstunnel/p3gxstunnel.cc | 376 ++++++++++++------ libretroshare/src/gxstunnel/p3gxstunnel.h | 37 +- .../src/gxstunnel/rsgxstunnelitems.h | 55 ++- libretroshare/src/retroshare/rsgxstunnel.h | 11 +- 4 files changed, 307 insertions(+), 172 deletions(-) diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.cc b/libretroshare/src/gxstunnel/p3gxstunnel.cc index 3ebe11870..a6e465dfe 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.cc +++ b/libretroshare/src/gxstunnel/p3gxstunnel.cc @@ -32,6 +32,7 @@ #include "util/rsaes.h" #include "util/rsprint.h" +#include "util/rsmemory.h" #include #include @@ -57,9 +58,20 @@ static const uint32_t RS_GXS_TUNNEL_STATUS_CAN_TALK = 0x01 ; static const uint32_t RS_GXS_TUNNEL_STATUS_TUNNEL_DN = 0x02 ; static const uint32_t RS_GXS_TUNNEL_STATUS_REMOTELY_CLOSED = 0x03 ; +static const uint32_t RS_GXS_TUNNEL_DELAY_BETWEEN_RESEND = 10 ; // re-send every 10 secs. + static const uint32_t GXS_TUNNEL_ENCRYPTION_HMAC_SIZE = SHA_DIGEST_LENGTH ; static const uint32_t GXS_TUNNEL_ENCRYPTION_IV_SIZE = 8 ; +p3GxsTunnelService::p3GxsTunnelService(RsGixs *pids) + : mGixs(pids), mGxsTunnelMtx("GXS tunnel") +{ + mTurtle = NULL ; + + // any value is fine here, even 0, since items in different RS sessions will use different AES keys. + global_item_counter = 0;//RSRandom::random_u64() ; +} + void p3GxsTunnelService::connectToTurtleRouter(p3turtle *tr) { mTurtle = tr ; @@ -68,12 +80,47 @@ void p3GxsTunnelService::connectToTurtleRouter(p3turtle *tr) void p3GxsTunnelService::flush() { + // Flush pending DH items. This is a higher priority, so we deal with them first. + + std::cerr << "p3GxsTunnelService::flush() flushing pending items." << std::endl; + { + RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + + while(!pendingDHItems.empty()) + if(locked_sendClearTunnelData(pendingDHItems.front()) ) + pendingDHItems.pop_front() ; + } + // Flush items that could not be sent, probably because of a Mutex protected zone. // - while(!pendingGxsTunnelItems.empty()) { - sendTurtleData(pendingGxsTunnelItems.front() ) ; - pendingGxsTunnelItems.pop_front() ; + RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + + while(!pendingGxsTunnelItems.empty()) + if(locked_sendEncryptedTunnelData(pendingGxsTunnelItems.front())) + pendingGxsTunnelItems.pop_front() ; + else + std::cerr << "Cannot send encrypted data item to tunnel " << pendingGxsTunnelItems.front()->PeerId() << std::endl; + } + + // Look at pending data item, and re-send them if necessary. + + { + RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + + time_t now = time(NULL) ; + + for(std::map::iterator it = pendingGxsTunnelDataItems.begin();it != pendingGxsTunnelDataItems.end();++it) + if(now > RS_GXS_TUNNEL_DELAY_BETWEEN_RESEND + it->second.last_sending_attempt) + { + if(locked_sendEncryptedTunnelData(it->second.data_item)) + { + std::cerr << " sending data item #" << std::hex << it->first << std::dec << std::endl; + it->second.last_sending_attempt = now ; + } + else + std::cerr << " Cannot send item " << std::hex << it->first << std::dec << std::endl; + } } // TODO: also sweep GXS id map and disable any ID with no virtual peer id in the list. @@ -121,80 +168,108 @@ void p3GxsTunnelService::flush() } } -bool p3GxsTunnelService::handleIncomingItem(RsGxsTunnelItem *item) +// In this function the PeerId is the GXS tunnel ID. + +void p3GxsTunnelService::handleIncomingItem(const RsGxsTunnelId& tunnel_id,RsGxsTunnelItem *item) { - if(item == NULL) - return false ; + if(item == NULL) + return ; - switch(item->PacketSubType()) - { - case RS_PKT_SUBTYPE_GXS_TUNNEL_DH_PUBLIC_KEY: handleRecvDHPublicKey(dynamic_cast(item)) ; break ; - return true ; + // We have 3 things to do: + // + // 1 - if it's a data item, send an ACK + // 2 - if it's an ack item, mark the item as properly received, and remove it from the queue + // 3 - if it's a status item, act accordingly. -#warning need to implement tunnel data handling here - case RS_PKT_SUBTYPE_GXS_TUNNEL_DATA: - return true ; - -#warning need to implement tunnel data ACK handling here - case RS_PKT_SUBTYPE_GXS_TUNNEL_DATA_ACK: - return true ; - - case RS_PKT_SUBTYPE_GXS_TUNNEL_STATUS: handleRecvStatusItem(dynamic_cast(item)) ; - return true ; + switch(item->PacketSubType()) + { - default: - return false ; - } + case RS_PKT_SUBTYPE_GXS_TUNNEL_DATA: handleRecvTunnelDataItem(tunnel_id,dynamic_cast(item)) ; + break ; - return false ; + case RS_PKT_SUBTYPE_GXS_TUNNEL_DATA_ACK: handleRecvTunnelDataAckItem(tunnel_id,dynamic_cast(item)) ; + break ; + + case RS_PKT_SUBTYPE_GXS_TUNNEL_STATUS: handleRecvStatusItem(tunnel_id,dynamic_cast(item)) ; + break ; + + default: + std::cerr << "(EE) impossible situation. DH items should be handled at the service level" << std::endl; + } + + delete item ; } -//#warning is this function still used?? -//bool p3GxsTunnelService::handleOutgoingItem(RsGxsTunnelItem *item) -//{ -// { -// RS_STACK_MUTEX(mGxsTunnelMtx) ; -// -// std::map::const_iterator it=_gxs_tunnel_contacts.find(RsGxsId(item->PeerId())); -// -// if(it == _gxs_tunnel_contacts.end()) -// return false ; -// } -// -//#ifdef CHAT_DEBUG -// std::cerr << "p3GxsTunnelService::handleOutgoingItem(): sending to " << item->PeerId() << ": interpreted as a distant chat virtual peer id." << std::endl; -//#endif -// sendTurtleData(item) ; -// return true; -//} +void p3GxsTunnelService::handleRecvTunnelDataAckItem(const RsGxsTunnelId& id,RsGxsTunnelDataAckItem *item) +{ + RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + + std::cerr << "p3GxsTunnelService::handling RecvTunnelDataAckItem()" << std::endl; + std::cerr << " item counter = " << std::hex << item->unique_item_counter << std::dec << std::endl; + + // remove it from the queue. + + std::map::iterator it = pendingGxsTunnelDataItems.find(item->unique_item_counter) ; + + if(it == pendingGxsTunnelDataItems.end()) + { + std::cerr << " (EE) item number " << std::hex << item->unique_item_counter << " is unknown. This is unexpected." << std::endl; + return ; + } + + delete it->second.data_item ; + pendingGxsTunnelDataItems.erase(it) ; +} -void p3GxsTunnelService::handleRecvStatusItem(RsGxsTunnelStatusItem *cs) +void p3GxsTunnelService::handleRecvTunnelDataItem(const RsGxsTunnelId& tunnel_id,RsGxsTunnelDataItem *item) +{ + // imediately send an ACK for this item + + RsGxsTunnelDataAckItem *ackitem = new RsGxsTunnelDataAckItem ; + + ackitem->unique_item_counter = item->unique_item_counter ; + ackitem->PeerId(item->PeerId()); + + { + RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + pendingGxsTunnelItems.push_back(ackitem) ; // we use the queue that does not need an ACK, in order to avoid an infinite loop ;-) + } + + // notify the client for the received data + + std::cerr << "p3GxsTunnelService::handleRecvTunnelDataItem()" << std::endl; + std::cerr << " data size = " << item->data_size << std::endl; + std::cerr << " service id = " << std::hex << item->service_id << std::dec << std::endl; + std::cerr << " counter id = " << std::hex << item->unique_item_counter << std::dec << std::endl; + + RsGxsTunnelClientService *service = NULL ; + { + RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + std::map::const_iterator it = mRegisteredServices.find(item->service_id) ; + + if(it == mRegisteredServices.end()) + { + std::cerr << " (EE) no registered service with ID " << std::hex << item->service_id << std::dec << ". Rejecting item." << std::endl; + return ; + } + service = it->second ; + } + + service->receiveData(tunnel_id,item->data,item->data_size) ; + + item->data = NULL ; // avoids deletion, since the client has the memory now + item->data_size = 0 ; +} + +void p3GxsTunnelService::handleRecvStatusItem(const RsGxsTunnelId& tunnel_id, RsGxsTunnelStatusItem *cs) { if(cs->flags & RS_GXS_TUNNEL_FLAG_CLOSING_DISTANT_CONNECTION) - { - RsGxsTunnelId tunnel_id ; - TurtleVirtualPeerId vpid = cs->PeerId() ; - - { - RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - - std::map::iterator it = _gxs_tunnel_virtual_peer_ids.find(vpid) ; - - if(it == _gxs_tunnel_virtual_peer_ids.end()) - { - std::cerr << " (EE) Cannot find hash in gxs_tunnel peer list!!" << std::endl; - return ; - } - tunnel_id = it->second.tunnel_id ; - } - markGxsTunnelAsClosed(tunnel_id); - } // nothing more to do, because the decryption routing will update the last_contact time when decrypting. if(cs->flags & RS_GXS_TUNNEL_FLAG_KEEP_ALIVE) - std::cerr << "GxsTunnelService::handleRecvGxsTunnelStatusItem(): received keep alive packet for inactive tunnel! peerId=" << cs->PeerId() << std::endl; + std::cerr << "GxsTunnelService::handleRecvGxsTunnelStatusItem(): received keep alive packet for inactive tunnel! peerId=" << cs->PeerId() << " tunnel=" << tunnel_id << std::endl; } bool p3GxsTunnelService::handleTunnelRequest(const RsFileHash& hash,const RsPeerId& /*peer_id*/) @@ -408,7 +483,6 @@ void p3GxsTunnelService::receiveTurtleData(RsTurtleGenericTunnelItem *gitem,cons // Now try deserialise the decrypted data to make an RsItem out of it. // -#warning needs proper passing of item to client RsItem *citem = RsGxsTunnelSerialiser().deserialise(&((uint8_t*)item->data_bytes)[8],&item->data_size-8) ; if(citem == NULL) @@ -419,11 +493,12 @@ void p3GxsTunnelService::receiveTurtleData(RsTurtleGenericTunnelItem *gitem,cons // DH key items are sent even before we know who we speak to, so the virtual peer id is used in this // case only. - - if(dynamic_cast(citem) != NULL) + RsGxsTunnelDHPublicKeyItem *dhitem = dynamic_cast(citem) ; + + if(dhitem != NULL) { - citem->PeerId(virtual_peer_id) ; - handleIncomingItem(dynamic_cast(citem)) ; + dhitem->PeerId(virtual_peer_id) ; + handleRecvDHPublicKey(dhitem) ; } else std::cerr << "(EE) Deserialiased item has unexpected type." << std::endl; @@ -444,6 +519,7 @@ bool p3GxsTunnelService::handleEncryptedData(const uint8_t *data_bytes,uint32_t #endif RsGxsTunnelItem *citem = NULL; + RsGxsTunnelId tunnel_id; { RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ @@ -462,7 +538,7 @@ bool p3GxsTunnelService::handleEncryptedData(const uint8_t *data_bytes,uint32_t return true ; } - RsGxsTunnelId tunnel_id = it->second.tunnel_id ; + tunnel_id = it->second.tunnel_id ; std::map::iterator it2 = _gxs_tunnel_contacts.find(tunnel_id) ; if(it2 == _gxs_tunnel_contacts.end()) @@ -534,7 +610,7 @@ bool p3GxsTunnelService::handleEncryptedData(const uint8_t *data_bytes,uint32_t #ifdef DEBUG_GXS_TUNNEL std::cerr << "(II) Setting peer id to " << citem->PeerId() << std::endl; #endif - handleIncomingItem(citem) ; // Treats the item, and deletes it + handleIncomingItem(tunnel_id,citem) ; // Treats the item, and deletes it return true ; } @@ -792,7 +868,7 @@ bool p3GxsTunnelService::locked_sendDHPublicKey(const DH *dh,const RsGxsId& own_ dhitem->print(std::cerr, 2) ; std::cerr << std::endl; #endif - pendingGxsTunnelItems.push_back(dhitem) ; // sent off-mutex to avoid deadlocking. + pendingDHItems.push_back(dhitem) ; // sent off-mutex to avoid deadlocking. return true ; } @@ -841,77 +917,68 @@ bool p3GxsTunnelService::locked_initDHSessionKey(DH *& dh) // Encrypts and sends the item. -void p3GxsTunnelService::sendTurtleData(RsGxsTunnelItem *item) +bool p3GxsTunnelService::locked_sendClearTunnelData(RsGxsTunnelDHPublicKeyItem *item) { #ifdef DEBUG_GXS_TUNNEL - std::cerr << "GxsTunnelService::sendTurtleData(): try sending item " << (void*)item << " to peer " << item->PeerId() << std::endl; + std::cerr << "GxsTunnelService::sendClearTunnelData(): try sending item " << (void*)item << " to peer " << item->PeerId() << std::endl; #endif - if(dynamic_cast(item) != NULL) + // make a TurtleGenericData item out of it, and send it in clear. + // + RsTurtleGenericDataItem *gitem = new RsTurtleGenericDataItem ; + + uint32_t rssize = item->serial_size() ; + + gitem->data_size = rssize + 8 ; + gitem->data_bytes = malloc(rssize+8) ; + + // by convention, we use a IV of 0 for unencrypted data. + memset(gitem->data_bytes,0,8) ; + + if(!item->serialise(&((uint8_t*)gitem->data_bytes)[8],rssize)) { - // make a TurtleGenericData item out of it, and send it in clear. - // - RsTurtleGenericDataItem *gitem = new RsTurtleGenericDataItem ; - - uint32_t rssize = item->serial_size() ; - - gitem->data_size = rssize + 8 ; - gitem->data_bytes = malloc(rssize+8) ; - - // by convention, we use a IV of 0 for unencrypted data. - memset(gitem->data_bytes,0,8) ; - - if(!item->serialise(&((uint8_t*)gitem->data_bytes)[8],rssize)) - { - std::cerr << "(EE) Could not serialise item!!!" << std::endl; - delete gitem ; - delete item ; - return ; - } + std::cerr << "(EE) Could not serialise item!!!" << std::endl; + delete gitem ; + return false; + } #ifdef DEBUG_GXS_TUNNEL - std::cerr << " GxsTunnelService::sendTurtleData(): Sending clear data to virtual peer: " << item->PeerId() << std::endl; - std::cerr << " gitem->data_size = " << gitem->data_size << std::endl; - std::cerr << " data = " << RsUtil::BinToHex((char*)gitem->data_bytes,gitem->data_size) ; - std::cerr << std::endl; + std::cerr << " GxsTunnelService::sendClearTunnelData(): Sending clear data to virtual peer: " << item->PeerId() << std::endl; + std::cerr << " gitem->data_size = " << gitem->data_size << std::endl; + std::cerr << " data = " << RsUtil::BinToHex((char*)gitem->data_bytes,gitem->data_size) ; + std::cerr << std::endl; #endif - mTurtle->sendTurtleData(item->PeerId(),gitem) ; - } - else - { - uint32_t rssize = item->serial_size(); - uint8_t *buff = (uint8_t*)malloc(rssize) ; - - if(!item->serialise(buff,rssize)) - { - std::cerr << "(EE) GxsTunnelService::sendTurtleData(): Could not serialise item!" << std::endl; - free(buff) ; - delete item ; - return ; - } - - sendEncryptedTurtleData(buff,rssize,item->PeerId()) ; - - free(buff) ; - } - delete item ; + mTurtle->sendTurtleData(item->PeerId(),gitem) ; + + return true ; } -void p3GxsTunnelService::sendEncryptedTurtleData(const uint8_t *buff,uint32_t rssize,const TurtleVirtualPeerId& vpid) +// Sends this item using secured/authenticated method, thx to the establshed cryptographic channel. + +bool p3GxsTunnelService::locked_sendEncryptedTunnelData(RsGxsTunnelItem *item) { + uint32_t rssize = item->serial_size(); + RsTemporaryMemory buff(rssize) ; + + if(!item->serialise(buff,rssize)) + { + std::cerr << "(EE) GxsTunnelService::sendEncryptedTunnelData(): Could not serialise item!" << std::endl; + return false; + } + uint8_t aes_key[GXS_TUNNEL_AES_KEY_SIZE] ; uint64_t IV = 0; #ifdef DEBUG_GXS_TUNNEL - std::cerr << "Sending encrypted data to tunnel wuth vpid " << vpid << std::endl; + std::cerr << "Sending encrypted data to tunnel wuth vpid " << item->PeerId() << std::endl; #endif - RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - + TurtleVirtualPeerId vpid = item->PeerId() ; + std::map::const_iterator it2 = _gxs_tunnel_virtual_peer_ids.find(vpid) ; if(it2 == _gxs_tunnel_virtual_peer_ids.end()) { std::cerr << "(EE) no virtual peer " << vpid << ". Something's wrong!" << std::endl; - return ; + return false; } std::map::iterator it = _gxs_tunnel_contacts.find(it2->second.tunnel_id) ; @@ -919,12 +986,12 @@ void p3GxsTunnelService::sendEncryptedTurtleData(const uint8_t *buff,uint32_t rs if(it == _gxs_tunnel_contacts.end()) { std::cerr << "(EE) Cannot find contact key info for virtual peer id " << vpid << ". Cannot send message!" << std::endl; - return ; + return false; } if(it->second.status != RS_GXS_TUNNEL_STATUS_CAN_TALK) { std::cerr << "(EE) Cannot talk to vpid " << vpid << ". Tunnel status is: " << it->second.status << std::endl; - return ; + return false; } memcpy(aes_key,it->second.aes_key,GXS_TUNNEL_AES_KEY_SIZE) ; @@ -933,19 +1000,19 @@ void p3GxsTunnelService::sendEncryptedTurtleData(const uint8_t *buff,uint32_t rs while(IV == 0) IV = RSRandom::random_u64() ; // make a random 8 bytes IV, that is not 0 #ifdef DEBUG_GXS_TUNNEL - std::cerr << "GxsTunnelService::sendTurtleData(): tunnel found. Encrypting data." << std::endl; + std::cerr << "GxsTunnelService::sendEncryptedTunnelData(): 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); + RsTemporaryMemory encrypted_data(encrypted_size) ; 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 ; - return ; + return false; } // make a TurtleGenericData item out of it: @@ -962,21 +1029,21 @@ void p3GxsTunnelService::sendEncryptedTurtleData(const uint8_t *buff,uint32_t rs memcpy(& (((uint8_t*)gitem->data_bytes)[GXS_TUNNEL_ENCRYPTION_HMAC_SIZE+GXS_TUNNEL_ENCRYPTION_IV_SIZE]),encrypted_data,encrypted_size) ; - delete[] encrypted_data ; - #ifdef DEBUG_GXS_TUNNEL std::cerr << " Using IV: " << std::hex << IV << std::dec << std::endl; std::cerr << " Using Key: " << RsUtil::BinToHex((char*)aes_key,GXS_TUNNEL_AES_KEY_SIZE) ; std::cerr << std::endl; std::cerr << " hmac: " << RsUtil::BinToHex((char*)gitem->data_bytes,GXS_TUNNEL_ENCRYPTION_HMAC_SIZE) ; #endif #ifdef DEBUG_GXS_TUNNEL - std::cerr << "GxsTunnelService::sendTurtleData(): Sending encrypted data to virtual peer: " << virtual_peer_id << std::endl; + std::cerr << "GxsTunnelService::sendEncryptedTunnelData(): Sending encrypted data to virtual peer: " << virtual_peer_id << std::endl; std::cerr << " gitem->data_size = " << gitem->data_size << std::endl; std::cerr << " serialised data = " << RsUtil::BinToHex((char*)gitem->data_bytes,gitem->data_size) ; std::cerr << std::endl; #endif mTurtle->sendTurtleData(virtual_peer_id,gitem) ; + + return true ; } bool p3GxsTunnelService::requestSecuredTunnel(const RsGxsId& to_gxs_id, const RsGxsId& from_gxs_id, RsGxsTunnelId &tunnel_id, uint32_t& error_code) @@ -1009,6 +1076,55 @@ bool p3GxsTunnelService::requestSecuredTunnel(const RsGxsId& to_gxs_id, const Rs return true ; } +bool p3GxsTunnelService::sendData(const RsGxsTunnelId &tunnel_id, uint32_t service_id, const uint8_t *data, uint32_t size) +{ + // make sure that the tunnel ID is registered. + + std::cerr << "p3GxsTunnelService::sendData()" << std::endl; + std::cerr << " tunnel id : " << tunnel_id << std::endl; + std::cerr << " data size : " << size << std::endl; + std::cerr << " service id: " << std::hex << service_id << std::dec << std::endl; + + RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + + std::map::const_iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; + + if(it == _gxs_tunnel_contacts.end()) + { + std::cerr << " (EE) no tunnel known with this ID. Sorry!" << std::endl; + return false ; + } + + // make sure the service is registered. + + if(mRegisteredServices.find(service_id) == mRegisteredServices.end()) + { + std::cerr << " (EE) no service registered with this ID. Please call rsGxsTunnel->registerClientService() at some point." << std::endl; + return false ; + } + + std::cerr << " verifications fine! Storing in out queue with:" << std::endl; + + RsGxsTunnelDataItem *item = new RsGxsTunnelDataItem ; + + item->unique_item_counter = global_item_counter++; // this allows to make the item unique + item->flags = 0; // not used yet. + item->service_id = service_id; + item->data_size = size; // encrypted data size + item->data = (uint8_t*)malloc(size); // encrypted data + memcpy(item->data,data,size) ; + + GxsTunnelData& tdata( pendingGxsTunnelDataItems[item->unique_item_counter] ) ; + + tdata.data_item = item ; + tdata.last_sending_attempt = 0 ; // never sent until now + + std::cerr << " counter id : " << std::hex << item->unique_item_counter << std::dec << std::endl; + + return true ; +} + + void p3GxsTunnelService::startClientGxsTunnelConnection(const RsGxsId& to_gxs_id,const RsGxsId& from_gxs_id,RsGxsTunnelId& tunnel_id) { // compute a random hash for that pair, and init the DH session for it so that we can recognise it when we get the virtual peer for it. @@ -1158,7 +1274,7 @@ bool p3GxsTunnelService::closeExistingTunnel(const RsGxsTunnelId& tunnel_id) cs->flags = RS_GXS_TUNNEL_FLAG_CLOSING_DISTANT_CONNECTION; cs->PeerId(vpid) ; - sendTurtleData(cs) ; // that needs to be done off-mutex and before we close the tunnel. + locked_sendEncryptedTunnelData(cs) ; // that needs to be done off-mutex and before we close the tunnel also ignoring failure. #ifdef DEBUG_GXS_TUNNEL std::cerr << " This is client side. Stopping tunnel manageement for tunnel_id " << tunnel_id << std::endl; diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.h b/libretroshare/src/gxstunnel/p3gxstunnel.h index ee7ec62cf..10441ecba 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.h +++ b/libretroshare/src/gxstunnel/p3gxstunnel.h @@ -116,24 +116,23 @@ static const uint32_t GXS_TUNNEL_AES_KEY_SIZE = 16 ; class p3GxsTunnelService: public RsGxsTunnelService, public RsTurtleClientService { public: - p3GxsTunnelService(RsGixs *pids) - : mGixs(pids), mGxsTunnelMtx("GXS tunnel") - { - mTurtle = NULL ; - } - + p3GxsTunnelService(RsGixs *pids) ; virtual void connectToTurtleRouter(p3turtle *) ; // Creates the invite if the public key of the distant peer is available. // Om success, stores the invite in the map above, so that we can respond to tunnel requests. // virtual bool requestSecuredTunnel(const RsGxsId& to_id,const RsGxsId& from_id,RsGxsTunnelId& tunnel_id,uint32_t& error_code) ; + virtual bool closeExistingTunnel(const RsGxsTunnelId &tunnel_id) ; virtual bool getTunnelStatus(const RsGxsTunnelId& tunnel_id,uint32_t &status); + virtual bool sendData(const RsGxsTunnelId& tunnel_id,uint32_t service_id,const uint8_t *data,uint32_t size) ; + + virtual bool registerClientService(uint32_t service_id,RsGxsTunnelClientService *service) ; private: void flush() ; - virtual bool handleIncomingItem(RsGxsTunnelItem *) ; + virtual void handleIncomingItem(const RsGxsTunnelId &tunnel_id, RsGxsTunnelItem *) ; class GxsTunnelPeerInfo { @@ -170,6 +169,12 @@ private: TurtleFileHash hash ; }; + struct GxsTunnelData + { + RsGxsTunnelDataItem *data_item ; + time_t last_sending_attempt ; + }; + // This maps contains the current peers to talk to with distant chat. // std::map _gxs_tunnel_contacts ; // current peers we can talk to @@ -178,7 +183,9 @@ private: // List of items to be sent asap. Used to store items that we cannot pass directly to // sendTurtleData(), because of Mutex protection. - std::list pendingGxsTunnelItems ; + std::map pendingGxsTunnelDataItems ; // items that need provable transport and encryption + std::list pendingGxsTunnelItems ; // items that do not need provable transport, yet need encryption + std::list pendingDHItems ; // Overloaded from RsTurtleClientService @@ -209,12 +216,15 @@ private: // item handling - void handleRecvStatusItem(RsGxsTunnelStatusItem *item) ; + void handleRecvStatusItem(const RsGxsTunnelId& id,RsGxsTunnelStatusItem *item) ; + void handleRecvTunnelDataItem(const RsGxsTunnelId& id,RsGxsTunnelDataItem *item) ; + void handleRecvTunnelDataAckItem(const RsGxsTunnelId &id, RsGxsTunnelDataAckItem *item); // Comunication with Turtle service - void sendTurtleData(RsGxsTunnelItem *) ; - void sendEncryptedTurtleData(const uint8_t *buff, uint32_t rssize, const TurtleVirtualPeerId &vpid) ; + bool locked_sendEncryptedTunnelData(RsGxsTunnelItem *item) ; + bool locked_sendClearTunnelData(RsGxsTunnelDHPublicKeyItem *item); // this limits the usage to DH items. Others should be encrypted! + bool handleEncryptedData(const uint8_t *data_bytes,uint32_t data_size,const TurtleFileHash& hash,const RsPeerId& virtual_peer_id) ; static TurtleFileHash hashFromVirtualPeerId(const DistantChatPeerId& peerId) ; // converts IDs so that we can talk to RsPeerId from outside @@ -224,4 +234,9 @@ private: p3turtle *mTurtle ; RsGixs *mGixs ; RsMutex mGxsTunnelMtx ; + + uint64_t global_item_counter ; + + std::map mRegisteredServices ; }; + diff --git a/libretroshare/src/gxstunnel/rsgxstunnelitems.h b/libretroshare/src/gxstunnel/rsgxstunnelitems.h index 3de2e207b..5151d119f 100644 --- a/libretroshare/src/gxstunnel/rsgxstunnelitems.h +++ b/libretroshare/src/gxstunnel/rsgxstunnelitems.h @@ -61,33 +61,32 @@ class RsGxsTunnelItem: public RsItem virtual uint32_t serial_size() = 0 ; // deserialise is handled using a constructor }; -// /*! -// * For sending distant communication data. The item is not encrypted after being serialised, but the data it. -// * The MAC is computed over encrypted data using the PFS key. All other items (except DH keys) are serialised, encrypted, and -// * sent as data in a RsGxsTunnelDataItem. -// * -// * @see p3GxsTunnelService -// */ -// class RsGxsTunnelDataItem: public RsGxsTunnelItem -// { -// public: -// RsGxsTunnelDataItem() :RsGxsTunnelItem(RS_PKT_SUBTYPE_GXS_TUNNEL_DATA) {} -// RsGxsTunnelDataItem(uint8_t subtype) :RsGxsTunnelItem(subtype) {} -// -// virtual ~RsGxsTunnelDataItem() {} -// 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 -// -// uint32_t sendTime; -// uint32_t flags; // mainly NEEDS_HACK? -// unsigned char *data ; // encrypted data -// uint32_t data_size ; // encrypted data size -// unsigned char IV[IV_LENGTH] ; // IV for the encrypted data -// unsigned char encrypted_data_mac[SHA_DIGEST_LENGTH] ; // mac of the encrypted data, in order to avoid -// }; +/*! + * For sending distant communication data. The item is not encrypted after being serialised, but the data it. + * The MAC is computed over encrypted data using the PFS key. All other items (except DH keys) are serialised, encrypted, and + * sent as data in a RsGxsTunnelDataItem. + * + * @see p3GxsTunnelService + */ +class RsGxsTunnelDataItem: public RsGxsTunnelItem +{ +public: + RsGxsTunnelDataItem() :RsGxsTunnelItem(RS_PKT_SUBTYPE_GXS_TUNNEL_DATA) {} + RsGxsTunnelDataItem(uint8_t subtype) :RsGxsTunnelItem(subtype) {} + + virtual ~RsGxsTunnelDataItem() {} + 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 + + uint64_t unique_item_counter; // this allows to make the item unique + uint32_t flags; // mainly NEEDS_HACK? + uint32_t service_id ; + uint32_t data_size ; // encrypted data size + unsigned char *data ; // encrypted data +}; // Used to send status of connection. This can be closing orders, flushing orders, etc. // These items are always sent encrypted. @@ -121,7 +120,7 @@ class RsGxsTunnelDataAckItem: public RsGxsTunnelItem 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 - Sha1CheckSum data_hash ; + uint64_t unique_item_counter ; // unique identifier for that item }; diff --git a/libretroshare/src/retroshare/rsgxstunnel.h b/libretroshare/src/retroshare/rsgxstunnel.h index cd3498877..efe6e59a2 100644 --- a/libretroshare/src/retroshare/rsgxstunnel.h +++ b/libretroshare/src/retroshare/rsgxstunnel.h @@ -49,7 +49,7 @@ public: // Data obtained from the corresponding GXS id. The memory ownership is transferred to the client, which // is responsible to free it using free() once used. - virtual void receiveData(const RsGxsTunnelId& id,const RsGxsId& from_id,unsigned char *data,uint32_t data_size) =0; + virtual void receiveData(const RsGxsTunnelId& id,unsigned char *data,uint32_t data_size) =0; }; class GxsTunnelInfo @@ -84,6 +84,11 @@ public: // Communication to other services. // //===================================================// + // Register a new client service. The service ID needs to be unique, and it's the coder's resonsibility to use an ID that is not used elsewhere + // for the same purpose. + + virtual bool registerClientService(uint32_t service_id,RsGxsTunnelClientService *service) =0; + // Asks for a tunnel. The service will request it to turtle router, and exchange a AES key using DH. // When the tunnel is secured, the client---here supplied as argument---will be notified. He can // then send data into the tunnel. The same tunnel may be used by different clients. @@ -91,9 +96,9 @@ public: virtual bool requestSecuredTunnel(const RsGxsId& to_id,const RsGxsId& from_id,RsGxsTunnelId& tunnel_id,uint32_t& error_code) =0 ; // Data is sent through the established tunnel, possibly multiple times, until reception is acknowledged. If the tunnel does not exist, the item is rejected and - // an error is issued. In any case, the memory ownership of the data is transferred to the tunnel service, so the client should not use it afterwards. + // an error is issued. In any case, the memory ownership of the data is *not* transferred to the tunnel service, so the client should delete it afterwards, if needed. - virtual bool sendData(RsGxsTunnelId tunnel_id, uint32_t client_service_id, const uint8_t *data, uint32_t data_size) =0; + virtual bool sendData(const RsGxsTunnelId tunnel_id, uint32_t client_service_id, const uint8_t *data, uint32_t data_size) =0; // Removes any established tunnel to this GXS id. This makes the tunnel refuse further data, but the tunnel will be however kept alive // until all pending data is flushed. All clients attached to the tunnel will be notified that the tunnel gets closed. From 26f4523f5f28a7b6e0df5bed917bc52e7f73593f Mon Sep 17 00:00:00 2001 From: csoler Date: Wed, 25 Nov 2015 17:34:13 -0500 Subject: [PATCH 09/26] fixed compilation --- libretroshare/src/gxstunnel/p3gxstunnel.cc | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.cc b/libretroshare/src/gxstunnel/p3gxstunnel.cc index a6e465dfe..b2f2d4880 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.cc +++ b/libretroshare/src/gxstunnel/p3gxstunnel.cc @@ -145,7 +145,6 @@ void p3GxsTunnelService::flush() { std::cerr << "(II) GxsTunnelService:: forcing new tunnel campain." << std::endl; -#warning make sure we can use random here. mTurtle->forceReDiggTunnels( randomHashFromDestinationGxsId(it->second.to_gxs_id) ); } } @@ -781,10 +780,6 @@ void p3GxsTunnelService::handleRecvDHPublicKey(RsGxsTunnelDHPublicKeyItem *item) cs->PeerId(vpid) ; pendingGxsTunnelItems.push_back(cs) ; - -#warning should notify client here - - //RsServer::notify()->notifyListChange(NOTIFY_LIST_PRIVATE_INCOMING_CHAT, NOTIFY_TYPE_ADD); } // Note: for some obscure reason, the typedef does not work here. Looks like a compiler error. So I use the primary type. @@ -1173,16 +1168,6 @@ void p3GxsTunnelService::startClientGxsTunnelConnection(const RsGxsId& to_gxs_id // Now ask the turtle router to manage a tunnel for that hash. mTurtle->monitorTunnels(hash,this,false) ; - -#warning check that this code should go. -#ifdef TO_BE_REMOVED - // spawn a status item so as to open the chat window. - RsGxsTunnelMsgItem *item = new RsGxsTunnelMsgItem; - item->message = "[Starting distant chat. Please wait for secure tunnel to be established]" ; - item->chatFlags = RS_CHAT_FLAG_PRIVATE ; - item->PeerId(RsPeerId(to_gxs_id)) ; - handleRecvGxsTunnelMsgItem(item) ; -#endif } TurtleFileHash p3GxsTunnelService::randomHashFromDestinationGxsId(const RsGxsId& destination) From a2e0f4196b93c5c7e719061a91a20b7d60e7522d Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 26 Nov 2015 20:40:06 -0500 Subject: [PATCH 10/26] updated GUI for new distant chat --- libretroshare/src/chat/distantchat.cc | 1055 +---------------- libretroshare/src/chat/distantchat.h | 97 +- libretroshare/src/chat/p3chatservice.cc | 25 +- libretroshare/src/gxstunnel/p3gxstunnel.cc | 8 +- libretroshare/src/gxstunnel/p3gxstunnel.h | 2 - .../src/gxstunnel/rsgxstunnelitems.cc | 4 + .../src/gxstunnel/rsgxstunnelitems.h | 4 +- libretroshare/src/pqi/p3historymgr.cc | 6 +- libretroshare/src/retroshare/rsgxstunnel.h | 12 +- libretroshare/src/retroshare/rsmsgs.h | 32 +- libretroshare/src/rsserver/p3msgs.cc | 10 +- libretroshare/src/rsserver/p3msgs.h | 6 +- libretroshare/src/rsserver/rsinit.cc | 10 +- retroshare-gui/src/gui/chat/ChatDialog.cpp | 7 +- .../src/gui/chat/ChatLobbyDialog.cpp | 3 +- .../src/gui/chat/PopupDistantChatDialog.cpp | 143 ++- .../src/gui/chat/PopupDistantChatDialog.h | 5 +- 17 files changed, 215 insertions(+), 1214 deletions(-) diff --git a/libretroshare/src/chat/distantchat.cc b/libretroshare/src/chat/distantchat.cc index e69e9aad8..b4891474d 100644 --- a/libretroshare/src/chat/distantchat.cc +++ b/libretroshare/src/chat/distantchat.cc @@ -31,6 +31,7 @@ #include "openssl/err.h" #include "util/rsaes.h" +#include "util/rsmemory.h" #include @@ -53,106 +54,43 @@ static const uint32_t RS_DISTANT_CHAT_DH_STATUS_UNINITIALIZED = 0x0000 ; static const uint32_t RS_DISTANT_CHAT_DH_STATUS_HALF_KEY_DONE = 0x0001 ; static const uint32_t RS_DISTANT_CHAT_DH_STATUS_KEY_AVAILABLE = 0x0002 ; -void DistantChatService::connectToTurtleRouter(p3turtle *tr) +static const uint32_t DISTANT_CHAT_GXS_TUNNEL_SERVICE_ID = 0xa0001 ; + +typedef RsGxsTunnelService::RsGxsTunnelId RsGxsTunnelId; + +void DistantChatService::connectToGxsTunnelService(RsGxsTunnelService *tr) { - mTurtle = tr ; - tr->registerTunnelService(this) ; + mGxsTunnels = tr ; + tr->registerClientService(DISTANT_CHAT_GXS_TUNNEL_SERVICE_ID,this) ; } -void DistantChatService::flush() -{ - // Flush items that could not be sent, probably because of a Mutex protected zone. - // - while(!pendingDistantChatItems.empty()) - { - sendTurtleData( pendingDistantChatItems.front() ) ; - pendingDistantChatItems.pop_front() ; - } - - // TODO: also sweep GXS id map and disable any ID with no virtual peer id in the list. - - RS_STACK_MUTEX(mDistantChatMtx); /********** STACK LOCKED MTX ******/ - - time_t now = time(NULL) ; - - for(std::map::iterator it(_distant_chat_contacts.begin());it!=_distant_chat_contacts.end();++it) - { - if(it->second.last_contact+20+DISTANT_CHAT_KEEP_ALIVE_TIMEOUT < now && it->second.status == RS_DISTANT_CHAT_STATUS_CAN_TALK) - { - std::cerr << "(II) DistantChatService:: connexion interrupted with peer." << std::endl; - it->second.status = RS_DISTANT_CHAT_STATUS_TUNNEL_DN ; - it->second.virtual_peer_id.clear() ; - - // Also reset turtle router monitoring so as to make the tunnel handling more responsive. If we don't do that, - // the TR will wait 60 secs for the tunnel to die, which causes a significant waiting time in the chat window. - - if(it->second.direction == RsTurtleGenericTunnelItem::DIRECTION_SERVER) - { - std::cerr << "(II) DistantChatService:: forcing new tunnel campain." << std::endl; - - mTurtle->forceReDiggTunnels( hashFromGxsId(it->first) ); - } - } - if(it->second.last_keep_alive_sent + DISTANT_CHAT_KEEP_ALIVE_TIMEOUT < now && it->second.status == RS_DISTANT_CHAT_STATUS_CAN_TALK) - { - RsChatStatusItem *cs = new RsChatStatusItem ; - - cs->status_string.clear() ; - cs->flags = RS_CHAT_FLAG_PRIVATE | RS_CHAT_FLAG_KEEP_ALIVE; - cs->PeerId(RsPeerId(it->first)) ; - - // we send off-mutex to avoid deadlock. - - pendingDistantChatItems.push_back(cs) ; - - it->second.last_keep_alive_sent = now ; -#ifdef DEBUG_DISTANT_CHAT - std::cerr << "(II) DistantChatService:: Sending keep alive packet to gxs id " << it->first << std::endl; -#endif - } - } -} - -bool DistantChatService::handleRecvItem(RsChatItem *item) -{ - if(item == NULL) - return false ; - - switch(item->PacketSubType()) - { - case RS_PKT_SUBTYPE_DISTANT_CHAT_DH_PUBLIC_KEY: handleRecvDHPublicKey(dynamic_cast(item)) ; break ; - return true ; - - case RS_PKT_SUBTYPE_CHAT_STATUS: - { - // Keep alive packets should not be forwarded to the GUI. It's just for keeping the tunnel up. - - RsChatStatusItem *csi = dynamic_cast(item) ; - if(csi != NULL && csi->flags & RS_CHAT_FLAG_KEEP_ALIVE) - return true ; - } - - default: - return false ; - } - - return false ; -} bool DistantChatService::handleOutgoingItem(RsChatItem *item) { + RsGxsTunnelId tunnel_id ; + { RS_STACK_MUTEX(mDistantChatMtx) ; - std::map::const_iterator it=_distant_chat_contacts.find(RsGxsId(item->PeerId())); + std::map::const_iterator it=mDistantChatContacts.find(DistantChatPeerId(item->PeerId())); - if(it == _distant_chat_contacts.end()) + if(it == mDistantChatContacts.end()) return false ; } #ifdef CHAT_DEBUG std::cerr << "p3ChatService::handleOutgoingItem(): sending to " << item->PeerId() << ": interpreted as a distant chat virtual peer id." << std::endl; #endif - sendTurtleData(item) ; + + uint32_t size = item->serial_size() ; + RsTemporaryMemory mem(size) ; + + if(!item->serialise(mem,size)) + { + std::cerr << "(EE) serialisation error. Something's really wrong!" << std::endl; + return false; + } + + mGxsTunnels->sendData( RsGxsTunnelId(item->PeerId()),DISTANT_CHAT_GXS_TUNNEL_SERVICE_ID,mem,size); return true; } @@ -167,946 +105,49 @@ void DistantChatService::handleRecvChatStatusItem(RsChatStatusItem *cs) std::cerr << "DistantChatService::handleRecvChatStatusItem(): received keep alive packet for inactive chat! peerId=" << cs->PeerId() << std::endl; } -bool DistantChatService::handleTunnelRequest(const RsFileHash& hash,const RsPeerId& /*peer_id*/) +bool DistantChatService::initiateDistantChatConnexion(const RsGxsId& to_gxs_id, const RsGxsId& from_gxs_id, DistantChatPeerId& dcpid, uint32_t& error_code) { - RsStackMutex stack(mDistantChatMtx); /********** STACK LOCKED MTX ******/ + RsGxsTunnelId tunnel_id ; + + if(!mGxsTunnels->requestSecuredTunnel(to_gxs_id,from_gxs_id,tunnel_id,error_code)) + return false ; + + dcpid = DistantChatPeerId(tunnel_id) ; - // look into owned GXS ids, and see if the hash corresponds to the expected hash - // - std::list own_id_list ; - rsIdentity->getOwnIds(own_id_list) ; + DistantChatContact& dc_contact(mDistantChatContacts[dcpid]) ; - // re-computing the hash from the GXS id allows to dynamically change the hash. That will allow - // the use of a contact passphrase, if needed. - - for(std::list::const_iterator it(own_id_list.begin());it!=own_id_list.end();++it) - if(hashFromGxsId(*it) == hash) - { -#ifdef DEBUG_DISTANT_CHAT - std::cerr << "DistantChatService::handleTunnelRequest: received tunnel request for hash " << hash << std::endl; - std::cerr << " answering true!" << std::endl; -#endif - return true ; - } - - return false ; -} - -void DistantChatService::addVirtualPeer(const TurtleFileHash& hash,const TurtleVirtualPeerId& virtual_peer_id,RsTurtleGenericTunnelItem::Direction dir) -{ -#ifdef DEBUG_DISTANT_CHAT - std::cerr << "DistantChatService:: received new virtual peer " << virtual_peer_id << " for hash " << hash << ", dir=" << dir << std::endl; -#endif - RsGxsId own_gxs_id ; - - { - RS_STACK_MUTEX(mDistantChatMtx); /********** STACK LOCKED MTX ******/ - - DistantChatDHInfo& dhinfo( _distant_chat_virtual_peer_ids[virtual_peer_id] ) ; - dhinfo.gxs_id.clear() ; - - if(dhinfo.dh != NULL) - DH_free(dhinfo.dh) ; - - dhinfo.dh = NULL ; - dhinfo.direction = dir ; - dhinfo.hash = hash ; - dhinfo.status = RS_DISTANT_CHAT_DH_STATUS_UNINITIALIZED ; - - // if( _distant_chat_virtual_peer_ids.find(virtual_peer_id) != _distant_chat_virtual_peer_ids.end()) - // { - // std::cerr << " Tunnel already registered for " << hash << " and virtual peer " << virtual_peer_id << ". Doing nothing." << std::endl; - // return ; - // } - - if(dir == RsTurtleGenericTunnelItem::DIRECTION_CLIENT) - { - // check that a tunnel is not already working for this hash. If so, give up. - - own_gxs_id = gxsIdFromHash(hash) ; - - } - else // client side - { - RsGxsId to_gxs_id = gxsIdFromHash(hash) ; - std::map::const_iterator it = _distant_chat_contacts.find(to_gxs_id) ; - - if(it == _distant_chat_contacts.end()) - { - std::cerr << "(EE) no pre-registered peer for hash " << hash << " on client side. This is a bug." << std::endl; - return ; - } - - if(it->second.status == RS_DISTANT_CHAT_STATUS_CAN_TALK) - { - std::cerr << " virtual peer is for a distant chat session that is already openned and alive. Giving it up." << std::endl; - return ; - } - - own_gxs_id = it->second.own_gxs_id ; - } - -#ifdef DEBUG_DISTANT_CHAT - std::cerr << " Creating new virtual peer ID entry and empty DH session key." << std::endl; -#endif - - } - -#ifdef DEBUG_DISTANT_CHAT - std::cerr << " Adding virtual peer " << virtual_peer_id << " for chat hash " << hash << std::endl; -#endif - - // Start a new DH session for this tunnel - RS_STACK_MUTEX(mDistantChatMtx); /********** STACK LOCKED MTX ******/ - - locked_restartDHSession(virtual_peer_id,own_gxs_id) ; -} - -void DistantChatService::locked_restartDHSession(const RsPeerId& virtual_peer_id,const RsGxsId& own_gxs_id) -{ -#ifdef DEBUG_DISTANT_CHAT - std::cerr << "Starting new DH session." << std::endl; -#endif - DistantChatDHInfo& dhinfo = _distant_chat_virtual_peer_ids[virtual_peer_id] ; - - dhinfo.status = RS_DISTANT_CHAT_DH_STATUS_UNINITIALIZED ; - - if(!locked_initDHSessionKey(dhinfo.dh)) - { - std::cerr << " (EE) Cannot start DH session. Something went wrong." << std::endl; - return ; - } - dhinfo.status = RS_DISTANT_CHAT_DH_STATUS_HALF_KEY_DONE ; - - if(!locked_sendDHPublicKey(dhinfo.dh,own_gxs_id,virtual_peer_id)) - std::cerr << " (EE) Cannot send DH public key. Something went wrong." << std::endl; -} - -void DistantChatService::removeVirtualPeer(const TurtleFileHash& hash,const TurtleVirtualPeerId& virtual_peer_id) -{ - bool tunnel_dn = false ; - -#ifdef DEBUG_DISTANT_CHAT - std::cerr << "Distant chat: Removing virtual peer " << virtual_peer_id << " for hash " << hash << std::endl; -#else - /* remove unused parameter warnings */ - (void) hash; -#endif - { - RsStackMutex stack(mDistantChatMtx); /********** STACK LOCKED MTX ******/ - - RsGxsId gxs_id ; - std::map::iterator it = _distant_chat_virtual_peer_ids.find(virtual_peer_id) ; - - if(it == _distant_chat_virtual_peer_ids.end()) - { - std::cerr << "(EE) Cannot remove virtual peer " << virtual_peer_id << ": not found in chat list!!" << std::endl; - return ; - } - - gxs_id = it->second.gxs_id ; - - if(it->second.dh != NULL) - DH_free(it->second.dh) ; - _distant_chat_virtual_peer_ids.erase(it) ; - - std::map::iterator it2 = _distant_chat_contacts.find(gxs_id) ; - - if(it2 == _distant_chat_contacts.end()) - { - std::cerr << "(EE) Cannot find GXS id " << gxs_id << " in contact list. Weird." << std::endl; - return ; - } - if(it2->second.virtual_peer_id == virtual_peer_id) - { - it2->second.status = RS_DISTANT_CHAT_STATUS_TUNNEL_DN ; - it2->second.virtual_peer_id.clear() ; - tunnel_dn = true ; - } - } - - if(tunnel_dn) - { - RsServer::notify()->notifyChatStatus(ChatId(RsGxsId(virtual_peer_id)),"tunnel is down...") ; - RsServer::notify()->notifyPeerStatusChanged(virtual_peer_id.toStdString(),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' } ; - - uint32_t mx = std::min(50u,size) ; - - for(uint32_t j = 0; j < mx; j++) - { - std::cerr << outl[ ( ((uint8_t*)data)[j]>>4) ] ; - std::cerr << outl[ ((uint8_t*)data)[j] & 0xf ] ; - } - if(size > 50) - std::cerr << "..." ; -} -#endif - -void DistantChatService::receiveTurtleData(RsTurtleGenericTunnelItem *gitem,const RsFileHash& hash, - const RsPeerId& virtual_peer_id,RsTurtleGenericTunnelItem::Direction direction) -{ -#ifdef DEBUG_DISTANT_CHAT - std::cerr << "DistantChatService::receiveTurtleData(): Received turtle data. " << std::endl; - std::cerr << " hash = " << hash << std::endl; - std::cerr << " vpid = " << virtual_peer_id << std::endl; - std::cerr << " acting as = " << direction << std::endl; -#else - /* remove unused parameter warnings */ - (void) direction; -#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 ; - } - // 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 ; - } - if(*((uint64_t*)item->data_bytes) != 0) - { -#ifdef DEBUG_DISTANT_CHAT - std::cerr << " Item is encrypted." << std::endl; -#endif - - // if cannot decrypt, it means the key is wrong. We need to re-negociate a new key. - - handleEncryptedData((uint8_t*)item->data_bytes,item->data_size,hash,virtual_peer_id) ; - } - else - { -#ifdef DEBUG_DISTANT_CHAT - std::cerr << " Item is not encrypted." << std::endl; -#endif - - // Now try deserialise the decrypted data to make an RsItem out of it. - // - RsItem *citem = RsChatSerialiser().deserialise(&((uint8_t*)item->data_bytes)[8],&item->data_size) ; - - if(citem == NULL) - { - std::cerr << "(EE) item could not be de-serialized. That is an error." << std::endl; - return ; - } - - // DH key items are sent even before we know who we speak to, so the virtual peer id is used in this - // case only. - - if(dynamic_cast(citem) != NULL) - { - citem->PeerId(virtual_peer_id) ; - handleIncomingItem(citem) ; - } - else - std::cerr << "(EE) Deserialiased item has unexpected type." << std::endl; - } -} - - -bool DistantChatService::handleEncryptedData(const uint8_t *data_bytes,uint32_t data_size,const TurtleFileHash& hash,const RsPeerId& virtual_peer_id) -{ -#ifdef DEBUG_DISTANT_CHAT - std::cerr << "handleEncryptedDataItem()" << std::endl; - std::cerr << " size = " << data_size << std::endl; - std::cerr << " data = " << (void*)data_bytes << std::endl; - std::cerr << " IV = " << std::hex << *(uint64_t*)data_bytes << std::dec << std::endl; - std::cerr << " data = " ; - - printBinaryData((uint8_t*)data_bytes,data_size) ; - std::cerr << std::endl; -#endif - - RsItem *citem = NULL; - - { - RS_STACK_MUTEX(mDistantChatMtx); /********** STACK LOCKED MTX ******/ - - uint32_t decrypted_size = RsAES::get_buffer_size(data_size-8); - uint8_t *decrypted_data = new uint8_t[decrypted_size]; - uint8_t aes_key[DISTANT_CHAT_AES_KEY_SIZE] ; - - std::map::iterator it = _distant_chat_virtual_peer_ids.find(virtual_peer_id) ; - - if(it == _distant_chat_virtual_peer_ids.end()) - { - std::cerr << "(EE) item is not coming out of a registered tunnel. Weird. hash=" << hash << ", peer id = " << virtual_peer_id << std::endl; - return true ; - } - - RsGxsId gxs_id = it->second.gxs_id ; - std::map::iterator it2 = _distant_chat_contacts.find(gxs_id) ; - - if(it2 == _distant_chat_contacts.end()) - { - std::cerr << "(EE) no GXS id data for ID=" << gxs_id << ". This is a bug." << std::endl; - return true ; - } - memcpy(aes_key,it2->second.aes_key,DISTANT_CHAT_AES_KEY_SIZE) ; - -#ifdef DEBUG_DISTANT_CHAT - std::cerr << " Using IV: " << std::hex << *(uint64_t*)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((uint8_t*)data_bytes,data_size) ; std::cerr << std::endl; -#endif - - if(!RsAES::aes_decrypt_8_16((uint8_t*)data_bytes+8,data_size-8,aes_key,(uint8_t*)data_bytes,decrypted_data,decrypted_size)) - { - std::cerr << "(EE) packet decryption failed." << std::endl; - std::cerr << "(EE) resetting new DH session." << std::endl; - - delete[] decrypted_data ; - - locked_restartDHSession(virtual_peer_id,it2->second.own_gxs_id) ; - - return false ; - } - it2->second.status = RS_DISTANT_CHAT_STATUS_CAN_TALK ; - it2->second.last_contact = time(NULL) ; - -#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. - // - citem = RsChatSerialiser().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 true; - } - - // DH key items are sent even before we know who we speak to, so the virtual peer id is used in this - // case only. - - citem->PeerId(RsPeerId(gxs_id)) ; - } - -#ifdef DEBUG_DISTANT_CHAT - std::cerr << "(II) Setting peer id to " << citem->PeerId() << std::endl; -#endif - handleIncomingItem(citem) ; // Treats the item, and deletes it - - return true ; -} - -void DistantChatService::handleRecvDHPublicKey(RsChatDHPublicKeyItem *item) -{ - if (!item) - { - return; - } - -#ifdef DEBUG_DISTANT_CHAT - std::cerr << "DistantChatService: Received DH public key." << std::endl; - item->print(std::cerr, 0) ; -#endif - - // Look for the current state of the key agreement. - - TurtleVirtualPeerId vpid = item->PeerId() ; - - RS_STACK_MUTEX(mDistantChatMtx); /********** STACK LOCKED MTX ******/ - - std::map::iterator it = _distant_chat_virtual_peer_ids.find(vpid) ; - - if(it == _distant_chat_virtual_peer_ids.end()) - { - std::cerr << " (EE) Cannot find hash in distant chat peer list!!" << std::endl; - return ; - } - - // Now check the signature of the DH public key item. - -#ifdef DEBUG_DISTANT_CHAT - std::cerr << " Checking signature. " << std::endl; -#endif - - uint32_t pubkey_size = BN_num_bytes(item->public_key) ; - unsigned char *data = (unsigned char *)malloc(pubkey_size) ; - BN_bn2bin(item->public_key, data) ; - - RsTlvSecurityKey signature_key ; - - // We need to get the key of the sender, but if the key is not cached, we - // need to get it first. So we let the system work for 2-3 seconds before - // giving up. Normally this would only cause a delay for uncached keys, - // which is rare. To force the system to cache the key, we first call for - // getIdDetails(). - // - RsIdentityDetails details ; - RsGxsId senders_id( item->signature.keyId ) ; - - for(int i=0;i<6;++i) - if(!mGixs->getKey(senders_id,signature_key) || signature_key.keyData.bin_data == NULL) - { -#ifdef DEBUG_DISTANT_CHAT - std::cerr << " Cannot get key. Waiting for caching. try " << i << "/6" << std::endl; -#endif - usleep(500 * 1000) ; // sleep for 500 msec. - } - else - break ; - - if(signature_key.keyData.bin_data == NULL) - { - std::cerr << " (EE) Key unknown for checking signature from " << senders_id << ", can't verify signature. Using key provided in DH packet (without adding to the keyring)." << std::endl; - - // check GXS key for defects. - - if(!GxsSecurity::checkPublicKey(item->gxs_key)) - { - std::cerr << "(SS) Security error in distant chat DH handshake: supplied key " << item->gxs_key.keyId << " is inconsistent. Refusing chat!" << std::endl; - return ; - } - if(item->gxs_key.keyId != item->signature.keyId) - { - std::cerr << "(SS) Security error in distant chat DH handshake: supplied key " << item->gxs_key.keyId << " is not the same than the item's signature key " << item->signature.keyId << ". Refusing chat!" << std::endl; - return ; - } - - signature_key = item->gxs_key ; - } - - if(!GxsSecurity::validateSignature((char*)data,pubkey_size,signature_key,item->signature)) - { - std::cerr << "(SS) Signature was verified and it doesn't check! This is a security issue!" << std::endl; - return ; - } - mGixs->timeStampKey(item->signature.keyId) ; - -#ifdef DEBUG_DISTANT_CHAT - std::cerr << " Signature checks! Sender's ID = " << senders_id << std::endl; - std::cerr << " Computing AES key" << std::endl; -#endif - - if(it->second.dh == NULL) - { - std::cerr << " (EE) no DH information for that peer. This is an error." << std::endl; - return ; - } - if(it->second.status == RS_DISTANT_CHAT_DH_STATUS_KEY_AVAILABLE) - { -#ifdef DEBUG_DISTANT_CHAT - std::cerr << " DH Session already set for this tunnel. Re-initing a new session!" << std::endl; -#endif - - locked_restartDHSession(vpid,_distant_chat_contacts[senders_id].own_gxs_id) ; - } - - // gets current key params. By default, should contain all null pointers. - // - it->second.gxs_id = senders_id ; - - // Looks for the DH params. If not there yet, create them. - // - int size = DH_size(it->second.dh) ; - unsigned char *key_buff = new unsigned char[size] ; - - if(size != DH_compute_key(key_buff,item->public_key,it->second.dh)) - { - std::cerr << " (EE) DH computation failed. Probably a bug. Error code=" << ERR_get_error() << std::endl; - return ; - } - it->second.status = RS_DISTANT_CHAT_DH_STATUS_KEY_AVAILABLE ; - -#ifdef DEBUG_DISTANT_CHAT - std::cerr << " DH key computation successed. New key in place." << std::endl; -#endif - DistantChatPeerInfo& pinfo(_distant_chat_contacts[senders_id]) ; - - // Now hash the key buffer into a 16 bytes key. - - assert(DISTANT_CHAT_AES_KEY_SIZE <= Sha1CheckSum::SIZE_IN_BYTES) ; - memcpy(pinfo.aes_key, RsDirUtil::sha1sum(key_buff,size).toByteArray(),DISTANT_CHAT_AES_KEY_SIZE) ; - delete[] key_buff ; - - pinfo.last_contact = time(NULL) ; - pinfo.last_keep_alive_sent = time(NULL) ; - pinfo.status = RS_DISTANT_CHAT_STATUS_CAN_TALK ; - pinfo.virtual_peer_id = vpid ; - pinfo.direction = it->second.direction ; - - if(pinfo.direction == RsTurtleGenericTunnelItem::DIRECTION_CLIENT) - pinfo.own_gxs_id = gxsIdFromHash(it->second.hash) ; - -#ifdef DEBUG_DISTANT_CHAT - std::cerr << " DH key computed. Tunnel is now secured!" << std::endl; - std::cerr << " Key computed: " ; printBinaryData(pinfo.aes_key,16) ; std::cerr << std::endl; - std::cerr << " Sending a ACK packet." << std::endl; -#endif - - // then we send an ACK packet to notify that the tunnel works. That's useful - // because it makes the peer at the other end of the tunnel know that all - // intermediate peer in the tunnel are able to transmit the data. - // However, it is not possible here to call sendTurtleData(), without dead-locking - // the turtle router, so we store the item is a list of items to be sent. - - RsChatStatusItem *cs = new RsChatStatusItem ; - - cs->status_string = "Tunnel is secured with PFS session. ACK received. You can talk!" ; - cs->flags = RS_CHAT_FLAG_PRIVATE | RS_CHAT_FLAG_ACK_DISTANT_CONNECTION; - cs->PeerId(RsPeerId(senders_id)); - - pendingDistantChatItems.push_back(cs) ; - - RsServer::notify()->notifyListChange(NOTIFY_LIST_PRIVATE_INCOMING_CHAT, NOTIFY_TYPE_ADD); -} - -bool DistantChatService::locked_sendDHPublicKey(const DH *dh,const RsGxsId& own_gxs_id,const RsPeerId& virtual_peer_id) -{ - if(dh == NULL) - { - std::cerr << " (EE) DH struct is not initialised! Error." << std::endl; - return false ; - } - - RsChatDHPublicKeyItem *dhitem = new RsChatDHPublicKeyItem ; - dhitem->public_key = BN_dup(dh->pub_key) ; - - // we should also sign the data and check the signature on the other end. - // - RsTlvKeySignature signature ; - RsTlvSecurityKey signature_key ; - RsTlvSecurityKey signature_key_public ; - - uint32_t error_status ; - - uint32_t size = BN_num_bytes(dhitem->public_key) ; - unsigned char *data = (unsigned char *)malloc(size) ; - BN_bn2bin(dhitem->public_key, data) ; - - if(!mGixs->signData((unsigned char*)data,size,own_gxs_id,signature,error_status)) - { - switch(error_status) - { - case RsGixs::RS_GIXS_ERROR_KEY_NOT_AVAILABLE: std::cerr << "(EE) Key is not available. Cannot sign." << std::endl; - break ; - default: std::cerr << "(EE) Unknown error when signing" << std::endl; - break ; - } - free(data) ; - delete(dhitem); - return false; - } - free(data) ; - - if(!mGixs->getKey(own_gxs_id,signature_key_public)) - { - std::cerr << " (EE) Could not retrieve own public key for ID = " << own_gxs_id << ". Giging up sending DH session params." << std::endl; - return false ; - } - - - assert(!(signature_key_public.keyFlags & RSTLV_KEY_TYPE_FULL)) ; - - dhitem->signature = signature ; - dhitem->gxs_key = signature_key_public ; - dhitem->PeerId(RsPeerId(virtual_peer_id)) ; // special case for DH items - -#ifdef DEBUG_DISTANT_CHAT - std::cerr << " Pushing DH session key item to pending distant messages..." << std::endl; - dhitem->print(std::cerr, 2) ; - std::cerr << std::endl; -#endif - pendingDistantChatItems.push_back(dhitem) ; // sent off-mutex to avoid deadlocking. - - return true ; -} - -bool DistantChatService::locked_initDHSessionKey(DH *& dh) -{ - static const std::string dh_prime_2048_hex = "B3B86A844550486C7EA459FA468D3A8EFD71139593FE1C658BBEFA9B2FC0AD2628242C2CDC2F91F5B220ED29AAC271192A7374DFA28CDDCA70252F342D0821273940344A7A6A3CB70C7897A39864309F6CAC5C7EA18020EF882693CA2C12BB211B7BA8367D5A7C7252A5B5E840C9E8F081469EBA0B98BCC3F593A4D9C4D5DF539362084F1B9581316C1F80FDAD452FD56DBC6B8ED0775F596F7BB22A3FE2B4753764221528D33DB4140DE58083DB660E3E105123FC963BFF108AC3A268B7380FFA72005A1515C371287C5706FFA6062C9AC73A9B1A6AC842C2764CDACFC85556607E86611FDF486C222E4896CDF6908F239E177ACC641FCBFF72A758D1C10CBB" ; - - if(dh != NULL) - { - DH_free(dh) ; - dh = NULL ; - } - - dh = DH_new() ; - - if(!dh) - { - std::cerr << " (EE) DH_new() failed." << std::endl; - return false ; - } - - BN_hex2bn(&dh->p,dh_prime_2048_hex.c_str()) ; - BN_hex2bn(&dh->g,"5") ; - - int codes = 0 ; - - if(!DH_check(dh, &codes) || codes != 0) - { - std::cerr << " (EE) DH check failed!" << std::endl; - return false ; - } - - if(!DH_generate_key(dh)) - { - std::cerr << " (EE) DH generate_key() failed! Error code = " << ERR_get_error() << std::endl; - return false ; - } -#ifdef DEBUG_DISTANT_CHAT - std::cerr << " (II) DH Session key inited." << std::endl; -#endif - return true ; -} - -void DistantChatService::sendTurtleData(RsChatItem *item) -{ -#ifdef DEBUG_DISTANT_CHAT - std::cerr << "DistantChatService::sendTurtleData(): try sending item " << (void*)item << " to peer " << item->PeerId() << std::endl; -#endif - - if(dynamic_cast(item) != NULL) - { - // make a TurtleGenericData item out of it, and send it in clear. - // - RsTurtleGenericDataItem *gitem = new RsTurtleGenericDataItem ; - - uint32_t rssize = item->serial_size() ; - - gitem->data_size = rssize + 8 ; - gitem->data_bytes = malloc(rssize+8) ; - - memset(gitem->data_bytes,0,8) ; - - if(!item->serialise(&((uint8_t*)gitem->data_bytes)[8],rssize)) - { - std::cerr << "(EE) Could not serialise item!!!" << std::endl; - delete gitem ; - delete item ; - return ; - } - -#ifdef DEBUG_DISTANT_CHAT - std::cerr << " DistantChatService::sendTurtleData(): Sending clear data to virtual peer: " << item->PeerId() << 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(item->PeerId(),gitem) ; - } - else - { - uint32_t rssize = item->serial_size(); - uint8_t *buff = (uint8_t*)malloc(rssize) ; - - if(!item->serialise(buff,rssize)) - { - std::cerr << "(EE) DistantChatService::sendTurtleData(): Could not serialise item!" << std::endl; - free(buff) ; - delete item ; - return ; - } - - sendEncryptedTurtleData(buff,rssize,RsGxsId(item->PeerId())) ; - - free(buff) ; - } - delete item ; -} - -void DistantChatService::sendEncryptedTurtleData(const uint8_t *buff,uint32_t rssize,const RsGxsId& gxs_id) -{ - uint8_t aes_key[DISTANT_CHAT_AES_KEY_SIZE] ; - uint64_t IV = 0; - -#ifdef DEBUG_DISTANT_CHAT - std::cerr << "Sending encrypted data to virtual gxs id " << gxs_id << std::endl; -#endif - RsStackMutex stack(mDistantChatMtx); /********** STACK LOCKED MTX ******/ - - std::map::iterator it = _distant_chat_contacts.find(gxs_id) ; - - if(it == _distant_chat_contacts.end()) - { - std::cerr << "(EE) Cannot find contact key info for ID " << gxs_id << ". Cannot send message!" << std::endl; - return ; - } - if(it->second.status != RS_DISTANT_CHAT_STATUS_CAN_TALK) - { - std::cerr << "(EE) Cannot talk to " << gxs_id << ". Tunnel status is: " << it->second.status << std::endl; - return ; - } - - memcpy(aes_key,it->second.aes_key,DISTANT_CHAT_AES_KEY_SIZE) ; - RsPeerId virtual_peer_id = it->second.virtual_peer_id ; - - while(IV == 0) IV = RSRandom::random_u64() ; // make a random 8 bytes IV, that is not 0 - -#ifdef DEBUG_DISTANT_CHAT - std::cerr << "DistantChatService::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); - -#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 ; - return ; - } - - // 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(& (((uint8_t*)gitem->data_bytes)[8]),encrypted_data,encrypted_size) ; - - delete[] encrypted_data ; - -#ifdef DEBUG_DISTANT_CHAT - std::cerr << "DistantChatService::sendTurtleData(): Sending encrypted data to 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 DistantChatService::initiateDistantChatConnexion(const RsGxsId& to_gxs_id,const RsGxsId& from_gxs_id,uint32_t& error_code) -{ - // should be a parameter. - - std::list lst ; - mGixs->getOwnIds(lst) ; - - bool found = false ; - for(std::list::const_iterator it = lst.begin();it!=lst.end();++it) - if(*it == from_gxs_id) - { - found=true; - break ; - } - - if(!found) - { - std::cerr << " (EE) Cannot start distant chat, since GXS id " << from_gxs_id << " is not available." << std::endl; - return false ; - } - RsGxsId own_gxs_id = from_gxs_id ; - - startClientDistantChatConnection(to_gxs_id,own_gxs_id) ; + dc_contact.from_id = from_gxs_id ; + dc_contact.to_id = to_gxs_id ; error_code = RS_DISTANT_CHAT_ERROR_NO_ERROR ; return true ; } -void DistantChatService::startClientDistantChatConnection(const RsGxsId& to_gxs_id,const RsGxsId& from_gxs_id) -{ - { - RsStackMutex stack(mDistantChatMtx); /********** STACK LOCKED MTX ******/ - - if(_distant_chat_contacts.find(to_gxs_id) != _distant_chat_contacts.end()) - { - std::cerr << "DistantChatService:: asking distant chat connexion to a peer who's already in a chat. Ignoring." << std::endl; - return ; - } - } - DistantChatPeerInfo info ; - - time_t now = time(NULL) ; - - info.last_contact = now ; - info.last_keep_alive_sent = now ; - info.status = RS_DISTANT_CHAT_STATUS_TUNNEL_DN ; - info.own_gxs_id = from_gxs_id ; - info.direction = RsTurtleGenericTunnelItem::DIRECTION_SERVER ; - info.virtual_peer_id.clear(); - - memset(info.aes_key,0,DISTANT_CHAT_AES_KEY_SIZE) ; - - { - RsStackMutex stack(mDistantChatMtx); /********** STACK LOCKED MTX ******/ - _distant_chat_contacts[to_gxs_id] = info ; - } - - // Now ask the turtle router to manage a tunnel for that hash. - - RsFileHash hash = hashFromGxsId(to_gxs_id) ; -#ifdef DEBUG_DISTANT_CHAT - std::cerr << "Starting distant chat to " << to_gxs_id << ", hash = " << hash << ", from " << from_gxs_id << std::endl; - std::cerr << "Asking turtle router to monitor tunnels for hash " << hash << std::endl; -#endif - - mTurtle->monitorTunnels(hash,this,false) ; - - // spawn a status item so as to open the chat window. - RsChatMsgItem *item = new RsChatMsgItem; - item->message = "[Starting distant chat. Please wait for secure tunnel to be established]" ; - item->chatFlags = RS_CHAT_FLAG_PRIVATE ; - item->PeerId(RsPeerId(to_gxs_id)) ; - handleRecvChatMsgItem(item) ; - -} -TurtleFileHash DistantChatService::hashFromGxsId(const RsGxsId& destination) -{ - // This is in prevision for the "secured GXS tunnel" service, which will need a service ID to register, - // just like GRouter does. - - static const uint32_t client = RS_SERVICE_TYPE_DISTANT_CHAT ; - - assert( destination.SIZE_IN_BYTES == 16) ; - assert(Sha1CheckSum::SIZE_IN_BYTES == 20) ; - - uint8_t bytes[20] ; - memcpy(bytes,destination.toByteArray(),16) ; - bytes[16] = 0 ; - bytes[17] = 0 ; - bytes[18] = (client >> 8) & 0xff ; - bytes[19] = client & 0xff ; - - // We could rehash this, with a secret key to get a HMAC. That would allow to publish secret distant chat - // passphrases. I'll do this later if needed. - - return Sha1CheckSum(bytes) ; -} -RsGxsId DistantChatService::gxsIdFromHash(const TurtleFileHash& sum) -{ - assert( RsGxsId::SIZE_IN_BYTES == 16) ; - assert(Sha1CheckSum::SIZE_IN_BYTES == 20) ; - - uint32_t client_id = sum.toByteArray()[19] + (sum.toByteArray()[18] << 8) ; - - if(client_id != RS_SERVICE_TYPE_DISTANT_CHAT) - std::cerr << "WARNING: DistantChatService::gxsIdFromHash(). Hash is not a distant file hash. This should not happen." << std::endl; - - return RsGxsId(sum.toByteArray());// takes the first 16 bytes -} -bool DistantChatService::getDistantChatStatus(const RsGxsId& gxs_id,uint32_t& status, RsGxsId *from_gxs_id) +bool DistantChatService::getDistantChatStatus(const DistantChatPeerId& tunnel_id, DistantChatPeerInfo& cinfo) { RsStackMutex stack(mDistantChatMtx); /********** STACK LOCKED MTX ******/ - std::map::const_iterator it = _distant_chat_contacts.find(gxs_id) ; + RsGxsTunnelService::GxsTunnelInfo tinfo ; - if(it != _distant_chat_contacts.end()) - { - status = it->second.status ; + if(!mGxsTunnels->getGxsTunnelInfo(RsGxsTunnelId(tunnel_id),tinfo)) + return false; - if(from_gxs_id != NULL) - *from_gxs_id = it->second.own_gxs_id ; + cinfo.to_id = tinfo.destination_gxs_id; + cinfo.own_id = tinfo.source_gxs_id; + cinfo.peer_id = tunnel_id; + cinfo.status = tinfo.tunnel_status; // see the values in rsmsgs.h - return true ; - } - - status = RS_DISTANT_CHAT_STATUS_UNKNOWN ; - - return false ; -} - -bool DistantChatService::closeDistantChatConnexion(const RsGxsId& gxs_id) -{ - // two cases: - // - client needs to stop asking for tunnels => remove the hash from the list of tunnelled files - // - server needs to only close the window and let the tunnel die. But the window should only open - // if a message arrives. - - { - RsStackMutex stack(mDistantChatMtx); /********** STACK LOCKED MTX ******/ - std::map::const_iterator it = _distant_chat_contacts.find(gxs_id) ; - - if(it == _distant_chat_contacts.end()) - { - std::cerr << "(EE) Cannot close distant chat connection. No connection openned for gxs id " << gxs_id << std::endl; - - // We don't know if we are server or client side, but mTurtle will not complain if the hash doesn't exist. - - mTurtle->stopMonitoringTunnels( hashFromGxsId(gxs_id) ); - - return false ; - } - if(it->second.direction == RsTurtleGenericTunnelItem::DIRECTION_CLIENT) // nothing more to do for server side. - return true ; - } - - // send a status item saying that we're closing the connection -#ifdef DEBUG_DISTANT_CHAT - std::cerr << " Sending a ACK to close the tunnel since we're managing it. Peer id=." << gxs_id << std::endl; -#endif - - RsChatStatusItem *cs = new RsChatStatusItem ; - - cs->status_string = "" ; - cs->flags = RS_CHAT_FLAG_PRIVATE | RS_CHAT_FLAG_CLOSING_DISTANT_CONNECTION; - cs->PeerId(RsPeerId(gxs_id)); - - sendTurtleData(cs) ; // that needs to be done off-mutex and before we close the tunnel. - -#ifdef DEBUG_DISTANT_CHAT - std::cerr << " This is client side. Stopping tunnel manageement for gxs_id " << gxs_id << std::endl; -#endif - mTurtle->stopMonitoringTunnels( hashFromGxsId(gxs_id) ); - { - RsStackMutex stack(mDistantChatMtx); /********** STACK LOCKED MTX ******/ - std::map::iterator it = _distant_chat_contacts.find(gxs_id) ; - - if(it == _distant_chat_contacts.end()) // server side. Nothing to do. - { - std::cerr << "(EE) Cannot close chat associated to GXS id " << gxs_id << ": not found." << std::endl; - return false ; - } - - _distant_chat_contacts.erase(it) ; - - // DistantChatService::removeVirtualPeerId() will be called by the turtle service. - } return true ; } -void DistantChatService::markDistantChatAsClosed(const RsGxsId& gxs_id) +bool DistantChatService::closeDistantChatConnexion(const DistantChatPeerId &tunnel_id) { - RS_STACK_MUTEX(mDistantChatMtx); /********** STACK LOCKED MTX ******/ - - std::map::iterator it = _distant_chat_contacts.find(gxs_id) ; - - if(it == _distant_chat_contacts.end()) - { - std::cerr << "(EE) Cannot mark distant chat connection as closed. No connection openned for gxs id " << gxs_id << ". Unexpected situation." << std::endl; - return ; - } - - if(it->second.direction == RsTurtleGenericDataItem::DIRECTION_CLIENT) - { -#ifdef DEBUG_DISTANT_CHAT - std::cerr << " This is server side. Marking distant chat as remotely closed for GXS id " << gxs_id << std::endl; -#endif - it->second.status = RS_DISTANT_CHAT_STATUS_REMOTELY_CLOSED ; - } + mGxsTunnels->closeExistingTunnel(RsGxsTunnelId(tunnel_id)) ; + + // also remove contact. Or do we wait for the notification? + + return true ; } + diff --git a/libretroshare/src/chat/distantchat.h b/libretroshare/src/chat/distantchat.h index 04d3f2817..cee527fdb 100644 --- a/libretroshare/src/chat/distantchat.h +++ b/libretroshare/src/chat/distantchat.h @@ -25,33 +25,34 @@ #pragma once -#include #include #include +#include class RsGixs ; static const uint32_t DISTANT_CHAT_AES_KEY_SIZE = 16 ; -class DistantChatService: public RsTurtleClientService +class DistantChatService: public RsGxsTunnelService::RsGxsTunnelClientService { public: - DistantChatService(RsGixs *pids) - : mGixs(pids), mDistantChatMtx("distant chat") + // So, public interface only uses DistandChatPeerId, but internally, this is converted into a RsGxsTunnelService::RsGxsTunnelId + + + DistantChatService(RsGixs *pids) : mDistantChatMtx("distant chat") { - mTurtle = NULL ; + mGxsTunnels = NULL ; } - void flush() ; - - virtual void connectToTurtleRouter(p3turtle *) ; + virtual void connectToGxsTunnelService(RsGxsTunnelService *tunnel_service) ; // 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 initiateDistantChatConnexion(const RsGxsId& to_gxs_id,const RsGxsId &from_gxs_id, uint32_t &error_code) ; - bool closeDistantChatConnexion(const RsGxsId& pid) ; - virtual bool getDistantChatStatus(const RsGxsId &gxs_id,uint32_t &status, RsGxsId *from_gxs_id=NULL) ; + bool initiateDistantChatConnexion(const RsGxsId& to_gxs_id, const RsGxsId &from_gxs_id, DistantChatPeerId& dcpid, uint32_t &error_code) ; + bool closeDistantChatConnexion(const DistantChatPeerId &tunnel_id) ; + + virtual bool getDistantChatStatus(const DistantChatPeerId &tunnel_id, DistantChatPeerInfo& cinfo) ; // derived in p3ChatService virtual void handleIncomingItem(RsItem *) = 0; @@ -62,78 +63,26 @@ public: void handleRecvChatStatusItem(RsChatStatusItem *cs) ; private: - class DistantChatPeerInfo + struct DistantChatContact { - public: - DistantChatPeerInfo() : last_contact(0), last_keep_alive_sent(0), status(0), direction(0) - { - memset(aes_key, 0, DISTANT_CHAT_AES_KEY_SIZE); - } - - time_t last_contact ; // used to keep track of working connexion - time_t last_keep_alive_sent ; // last time we sent a keep alive packet. - - unsigned char aes_key[DISTANT_CHAT_AES_KEY_SIZE] ; - - uint32_t status ; // info: do we have a tunnel ? - RsPeerId virtual_peer_id; // given by the turtle router. Identifies the tunnel. - RsGxsId own_gxs_id ; // gxs id we're using to talk. - RsTurtleGenericTunnelItem::Direction direction ; // specifiec wether we are client(managing the tunnel) or server. + RsGxsId from_id ; + RsGxsId to_id ; }; - - class DistantChatDHInfo - { - public: - DistantChatDHInfo() : dh(0), direction(0), status(0) {} - - DH *dh ; - RsGxsId gxs_id ; - RsTurtleGenericTunnelItem::Direction direction ; - uint32_t status ; - TurtleFileHash hash ; - }; - // This maps contains the current peers to talk to with distant chat. // - std::map _distant_chat_contacts ; // current peers we can talk to - std::map _distant_chat_virtual_peer_ids ; // current virtual peers. Used to figure out tunnels, etc. + std::map mDistantChatContacts ; // current peers we can talk to - // List of items to be sent asap. Used to store items that we cannot pass directly to - // sendTurtleData(), because of Mutex protection. + // Overloaded from RsGxsTunnelClientService + + virtual void notifyTunnelStatus(const RsGxsTunnelService::RsGxsTunnelId& tunnel_id,uint32_t tunnel_status) ; + virtual void receiveData(const RsGxsTunnelService::RsGxsTunnelId& id,unsigned char *data,uint32_t data_size) ; - std::list pendingDistantChatItems ; - - // Overloaded from RsTurtleClientService - - virtual bool handleTunnelRequest(const RsFileHash &hash,const RsPeerId& peer_id) ; - virtual void receiveTurtleData(RsTurtleGenericTunnelItem *item,const RsFileHash& hash,const RsPeerId& virtual_peer_id,RsTurtleGenericTunnelItem::Direction direction) ; - void addVirtualPeer(const TurtleFileHash&, const TurtleVirtualPeerId&,RsTurtleGenericTunnelItem::Direction dir) ; - void removeVirtualPeer(const TurtleFileHash&, const TurtleVirtualPeerId&) ; + // Utility functions. + void markDistantChatAsClosed(const RsGxsId &gxs_id) ; void startClientDistantChatConnection(const RsGxsId &to_gxs_id,const RsGxsId& from_gxs_id) ; - void locked_restartDHSession(const RsPeerId &virtual_peer_id, const RsGxsId &own_gxs_id) ; - //bool getHashFromVirtualPeerId(const TurtleVirtualPeerId& pid,RsFileHash& hash) ; - - static TurtleFileHash hashFromGxsId(const RsGxsId& destination) ; - static RsGxsId gxsIdFromHash(const TurtleFileHash& sum) ; - - void handleRecvDHPublicKey(RsChatDHPublicKeyItem *item) ; - bool locked_sendDHPublicKey(const DH *dh, const RsGxsId &own_gxs_id, const RsPeerId &virtual_peer_id) ; - bool locked_initDHSessionKey(DH *&dh); - DistantChatPeerId virtualPeerIdFromHash(const TurtleFileHash& hash ) ; // ... and to a hash for p3turtle - - - // Utility functions - - void sendTurtleData(RsChatItem *) ; - void sendEncryptedTurtleData(const uint8_t *buff,uint32_t rssize,const RsGxsId &gxs_id) ; - bool handleEncryptedData(const uint8_t *data_bytes,uint32_t data_size,const TurtleFileHash& hash,const RsPeerId& virtual_peer_id) ; - - static TurtleFileHash hashFromVirtualPeerId(const DistantChatPeerId& peerId) ; // converts IDs so that we can talk to RsPeerId from outside - - p3turtle *mTurtle ; - RsGixs *mGixs ; + RsGxsTunnelService *mGxsTunnels ; RsMutex mDistantChatMtx ; }; diff --git a/libretroshare/src/chat/p3chatservice.cc b/libretroshare/src/chat/p3chatservice.cc index 308cbc3b2..9e014432b 100644 --- a/libretroshare/src/chat/p3chatservice.cc +++ b/libretroshare/src/chat/p3chatservice.cc @@ -86,7 +86,7 @@ int p3ChatService::tick() receiveChatQueue(); DistributedChatService::flush() ; - DistantChatService::flush() ; + //DistantChatService::flush() ; return 0; } @@ -284,12 +284,15 @@ void p3ChatService::checkSizeAndSendMessage(RsChatMsgItem *msg) bool p3ChatService::isOnline(const RsPeerId& pid) { - // check if the id is a tunnel id or a peer id. - uint32_t status ; - if(getDistantChatStatus(RsGxsId(pid),status)) - return status == RS_DISTANT_CHAT_STATUS_CAN_TALK ; + // check if the id is a tunnel id or a peer id. + + uint32_t status ; + DistantChatPeerInfo dcpinfo; + + if(getDistantChatStatus(DistantChatPeerId(pid),dcpinfo)) + return dcpinfo.status == RS_DISTANT_CHAT_STATUS_CAN_TALK ; else - return mServiceCtrl->isPeerConnected(getServiceInfo().mServiceType, pid); + return mServiceCtrl->isPeerConnected(getServiceInfo().mServiceType, pid); } bool p3ChatService::sendChat(ChatId destination, std::string msg) @@ -767,6 +770,7 @@ void p3ChatService::handleRecvChatStatusItem(RsChatStatusItem *cs) #endif uint32_t status; + DistantChatPeerInfo dcpinfo; if(cs->flags & RS_CHAT_FLAG_REQUEST_CUSTOM_STATE) // no state here just a request. sendCustomState(cs->PeerId()) ; @@ -782,9 +786,9 @@ void p3ChatService::handleRecvChatStatusItem(RsChatStatusItem *cs) #endif sendCustomStateRequest(cs->PeerId()) ; } - else if(DistantChatService::getDistantChatStatus(RsGxsId(cs->PeerId()), status)) + else if(DistantChatService::getDistantChatStatus(DistantChatPeerId(cs->PeerId()), dcpinfo)) { - RsServer::notify()->notifyChatStatus(ChatId(RsGxsId(cs->PeerId())), cs->status_string) ; + RsServer::notify()->notifyChatStatus(ChatId(DistantChatPeerId(cs->PeerId())), cs->status_string) ; } else if(cs->flags & RS_CHAT_FLAG_PRIVATE) { @@ -817,8 +821,9 @@ void p3ChatService::initChatMessage(RsChatMsgItem *c, ChatMessage &m) } uint32_t status; - if(DistantChatService::getDistantChatStatus(RsGxsId(c->PeerId()), status)) - m.chat_id = ChatId(RsGxsId(c->PeerId())); + DistantChatPeerInfo dcpinfo; + if(DistantChatService::getDistantChatStatus(DistantChatPeerId(c->PeerId()), dcpinfo)) + m.chat_id = ChatId(DistantChatPeerId(c->PeerId())); if (c -> chatFlags & RS_CHAT_FLAG_PRIVATE) m.chatflags |= RS_CHAT_PRIVATE; diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.cc b/libretroshare/src/gxstunnel/p3gxstunnel.cc index b2f2d4880..b2c1fffae 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.cc +++ b/libretroshare/src/gxstunnel/p3gxstunnel.cc @@ -53,11 +53,6 @@ static const uint32_t RS_GXS_TUNNEL_DH_STATUS_UNINITIALIZED = 0x0000 ; static const uint32_t RS_GXS_TUNNEL_DH_STATUS_HALF_KEY_DONE = 0x0001 ; static const uint32_t RS_GXS_TUNNEL_DH_STATUS_KEY_AVAILABLE = 0x0002 ; -static const uint32_t RS_GXS_TUNNEL_STATUS_UNKNOWN = 0x00 ; -static const uint32_t RS_GXS_TUNNEL_STATUS_CAN_TALK = 0x01 ; -static const uint32_t RS_GXS_TUNNEL_STATUS_TUNNEL_DN = 0x02 ; -static const uint32_t RS_GXS_TUNNEL_STATUS_REMOTELY_CLOSED = 0x03 ; - static const uint32_t RS_GXS_TUNNEL_DELAY_BETWEEN_RESEND = 10 ; // re-send every 10 secs. static const uint32_t GXS_TUNNEL_ENCRYPTION_HMAC_SIZE = SHA_DIGEST_LENGTH ; @@ -1126,8 +1121,7 @@ void p3GxsTunnelService::startClientGxsTunnelConnection(const RsGxsId& to_gxs_id RsFileHash hash = randomHashFromDestinationGxsId(to_gxs_id) ; - RsGxsTunnelId tnl_id = makeGxsTunnelId(from_gxs_id,to_gxs_id) ; - tunnel_id = tnl_id ; + tunnel_id = makeGxsTunnelId(from_gxs_id,to_gxs_id) ; { RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.h b/libretroshare/src/gxstunnel/p3gxstunnel.h index 10441ecba..fa519fc84 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.h +++ b/libretroshare/src/gxstunnel/p3gxstunnel.h @@ -227,8 +227,6 @@ private: bool handleEncryptedData(const uint8_t *data_bytes,uint32_t data_size,const TurtleFileHash& hash,const RsPeerId& virtual_peer_id) ; - static TurtleFileHash hashFromVirtualPeerId(const DistantChatPeerId& peerId) ; // converts IDs so that we can talk to RsPeerId from outside - // local data p3turtle *mTurtle ; diff --git a/libretroshare/src/gxstunnel/rsgxstunnelitems.cc b/libretroshare/src/gxstunnel/rsgxstunnelitems.cc index e44102bc4..e08421120 100644 --- a/libretroshare/src/gxstunnel/rsgxstunnelitems.cc +++ b/libretroshare/src/gxstunnel/rsgxstunnelitems.cc @@ -232,6 +232,10 @@ std::ostream& RsChatAvatarItem::print(std::ostream &out, uint16_t indent) return out; } +RsGxsTunnelDHPublicKeyItem::~RsGxsTunnelDHPublicKeyItem() +{ + BN_free(public_key) ; +} RsItem *RsChatSerialiser::deserialise(void *data, uint32_t *pktsize) { uint32_t rstype = getRsItemId(data); diff --git a/libretroshare/src/gxstunnel/rsgxstunnelitems.h b/libretroshare/src/gxstunnel/rsgxstunnelitems.h index 5151d119f..8aea07f67 100644 --- a/libretroshare/src/gxstunnel/rsgxstunnelitems.h +++ b/libretroshare/src/gxstunnel/rsgxstunnelitems.h @@ -130,10 +130,10 @@ class RsGxsTunnelDataAckItem: public RsGxsTunnelItem class RsGxsTunnelDHPublicKeyItem: public RsGxsTunnelItem { public: - RsGxsTunnelDHPublicKeyItem() :RsGxsTunnelItem(RS_PKT_SUBTYPE_DISTANT_CHAT_DH_PUBLIC_KEY) {} + RsGxsTunnelDHPublicKeyItem() :RsGxsTunnelItem(RS_PKT_SUBTYPE_GXS_TUNNEL_DH_PUBLIC_KEY) {} RsGxsTunnelDHPublicKeyItem(void *data,uint32_t size) ; // deserialization - virtual ~RsGxsTunnelDHPublicKeyItem() { BN_free(public_key) ; } + virtual ~RsGxsTunnelDHPublicKeyItem() ; 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 ? diff --git a/libretroshare/src/pqi/p3historymgr.cc b/libretroshare/src/pqi/p3historymgr.cc index 60f279bd2..8b6887f23 100644 --- a/libretroshare/src/pqi/p3historymgr.cc +++ b/libretroshare/src/pqi/p3historymgr.cc @@ -104,9 +104,9 @@ void p3HistoryMgr::addMessage(const ChatMessage& cm) peerName = cm.chat_id.toGxsId().toStdString(); } else { uint32_t status; - RsGxsId from_gxs_id; - if (rsMsgs->getDistantChatStatus(cm.chat_id.toGxsId(), status, &from_gxs_id)) - peerName = from_gxs_id.toStdString(); + DistantChatPeerInfo dcpinfo; + if (rsMsgs->getDistantChatStatus(cm.chat_id.toPeerId(), dcpinfo)) + peerName = cm.chat_id.toPeerId().toStdString(); } enabled = true; } diff --git a/libretroshare/src/retroshare/rsgxstunnel.h b/libretroshare/src/retroshare/rsgxstunnel.h index efe6e59a2..f7cdc708f 100644 --- a/libretroshare/src/retroshare/rsgxstunnel.h +++ b/libretroshare/src/retroshare/rsgxstunnel.h @@ -36,6 +36,11 @@ public: static const uint32_t RS_GXS_TUNNEL_ERROR_NO_ERROR = 0x0000 ; static const uint32_t RS_GXS_TUNNEL_ERROR_UNKNOWN_GXS_ID = 0x0001 ; + static const uint32_t RS_GXS_TUNNEL_STATUS_UNKNOWN = 0x00 ; + static const uint32_t RS_GXS_TUNNEL_STATUS_CAN_TALK = 0x01 ; + static const uint32_t RS_GXS_TUNNEL_STATUS_TUNNEL_DN = 0x02 ; + static const uint32_t RS_GXS_TUNNEL_STATUS_REMOTELY_CLOSED = 0x03 ; + typedef GXSTunnelId RsGxsTunnelId ; class RsGxsTunnelClientService @@ -50,6 +55,10 @@ public: // is responsible to free it using free() once used. virtual void receiveData(const RsGxsTunnelId& id,unsigned char *data,uint32_t data_size) =0; + + // Used by the creator of the service to supply a pointer to the GXS tunnel service for it to be able to send data etc. + + virtual void connectToGxsTunnelService(RsGxsTunnelService *tunnel_service) =0; }; class GxsTunnelInfo @@ -77,6 +86,7 @@ public: //===================================================// virtual bool getGxsTunnelsInfo(std::vector& infos) =0; + virtual bool getGxsTunnelInfo(const RsGxsTunnelId& tunnel_id,GxsTunnelInfo& info) =0; // retrieve the routing probabilities @@ -103,7 +113,7 @@ public: // Removes any established tunnel to this GXS id. This makes the tunnel refuse further data, but the tunnel will be however kept alive // until all pending data is flushed. All clients attached to the tunnel will be notified that the tunnel gets closed. - virtual bool closeExistingTunnel(const RsGxsId& to_id) =0; + virtual bool closeExistingTunnel(const RsGxsTunnelId& to_id) =0; //===================================================// // Routage feedback from other services // diff --git a/libretroshare/src/retroshare/rsmsgs.h b/libretroshare/src/retroshare/rsmsgs.h index d71544d15..793ed20be 100644 --- a/libretroshare/src/retroshare/rsmsgs.h +++ b/libretroshare/src/retroshare/rsmsgs.h @@ -100,7 +100,6 @@ typedef uint64_t ChatLobbyMsgId ; typedef std::string ChatLobbyNickName ; typedef RsPeerId DistantChatPeerId ; -//typedef GRouterKeyId DistantMsgPeerId ; typedef uint64_t MessageId ; @@ -253,12 +252,12 @@ 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_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_STATUS_REMOTELY_CLOSED 0x0004 -#define RS_DISTANT_CHAT_STATUS_WAITING_DH 0x0005 +#define RS_DISTANT_CHAT_STATUS_WAITING_DH 0x0005 #define RS_DISTANT_CHAT_ERROR_NO_ERROR 0x0000 #define RS_DISTANT_CHAT_ERROR_DECRYPTION_FAILED 0x0001 @@ -269,6 +268,14 @@ public: #define RS_DISTANT_CHAT_FLAG_SIGNED 0x0001 #define RS_DISTANT_CHAT_FLAG_SIGNATURE_OK 0x0002 +struct DistantChatPeerInfo +{ + RsGxsId to_id ; + RsGxsId own_id ; + DistantChatPeerId peer_id ; // this is the tunnel id actually + uint32_t status ; // see the values in rsmsgs.h +}; + // Identifier for an chat endpoint like // neighbour peer, distant peer, chatlobby, broadcast class ChatId @@ -372,15 +379,6 @@ class ChatLobbyInfo time_t last_activity ; // last recorded activity. Useful for removing dead lobbies. }; -struct DistantChatInviteInfo -{ - DistantChatPeerId pid ; // pid to contact the invite and refer to it. - std::string encrypted_radix64_string ; // encrypted radix string used to for the chat link - RsPgpId destination_pgp_id ; // pgp is of the destination of the chat link - time_t time_of_validity ; // time when te invite becomes unusable - uint32_t invite_flags ; // used to keep track of wether signature was ok or not. -}; - std::ostream &operator<<(std::ostream &out, const Rs::Msgs::MessageInfo &info); class RsMsgs; @@ -481,9 +479,9 @@ virtual ChatLobbyId createChatLobby(const std::string& lobby_name,const RsGxsId& /* Distant chat */ /****************************************/ -virtual bool initiateDistantChatConnexion(const RsGxsId& to_pid,const RsGxsId& from_pid,uint32_t& error_code) = 0; -virtual bool getDistantChatStatus(const RsGxsId& gxs_id,uint32_t& status, RsGxsId *from_gxs_id = NULL) = 0; -virtual bool closeDistantChatConnexion(const RsGxsId& pid) = 0; +virtual bool initiateDistantChatConnexion(const RsGxsId& to_pid,const RsGxsId& from_pid,DistantChatPeerId& pid,uint32_t& error_code) = 0; +virtual bool getDistantChatStatus(const DistantChatPeerId& pid,DistantChatPeerInfo& info)=0; +virtual bool closeDistantChatConnexion(const DistantChatPeerId& pid)=0; }; diff --git a/libretroshare/src/rsserver/p3msgs.cc b/libretroshare/src/rsserver/p3msgs.cc index 6ce2d4830..8d52fcc8b 100644 --- a/libretroshare/src/rsserver/p3msgs.cc +++ b/libretroshare/src/rsserver/p3msgs.cc @@ -523,15 +523,15 @@ void p3Msgs::getPendingChatLobbyInvites(std::list& invites) { mChatSrv->getPendingChatLobbyInvites(invites) ; } -bool p3Msgs::initiateDistantChatConnexion(const RsGxsId& to_gxs_id,const RsGxsId& from_gxs_id,uint32_t& error_code) +bool p3Msgs::initiateDistantChatConnexion(const RsGxsId& to_gxs_id,const RsGxsId& from_gxs_id,DistantChatPeerId& pid,uint32_t& error_code) { - return mChatSrv->initiateDistantChatConnexion(to_gxs_id,from_gxs_id,error_code) ; + return mChatSrv->initiateDistantChatConnexion(to_gxs_id,from_gxs_id,pid,error_code) ; } -bool p3Msgs::getDistantChatStatus(const RsGxsId &gxs_id,uint32_t &status,RsGxsId *from_gxs_id) +bool p3Msgs::getDistantChatStatus(const DistantChatPeerId& pid,DistantChatPeerInfo& info) { - return mChatSrv->getDistantChatStatus(gxs_id,status,from_gxs_id) ; + return mChatSrv->getDistantChatStatus(pid,info) ; } -bool p3Msgs::closeDistantChatConnexion(const RsGxsId& pid) +bool p3Msgs::closeDistantChatConnexion(const DistantChatPeerId &pid) { return mChatSrv->closeDistantChatConnexion(pid) ; } diff --git a/libretroshare/src/rsserver/p3msgs.h b/libretroshare/src/rsserver/p3msgs.h index 5599a8ee1..98e9da7de 100644 --- a/libretroshare/src/rsserver/p3msgs.h +++ b/libretroshare/src/rsserver/p3msgs.h @@ -155,9 +155,9 @@ class p3Msgs: public RsMsgs virtual bool getLobbyAutoSubscribe(const ChatLobbyId& lobby_id); virtual ChatLobbyId createChatLobby(const std::string& lobby_name,const RsGxsId& lobby_identity,const std::string& lobby_topic,const std::set& invited_friends,ChatLobbyFlags privacy_type) ; - virtual bool initiateDistantChatConnexion(const RsGxsId& to_gxs_id,const RsGxsId& from_gxs_id,uint32_t& error_code) ; - virtual bool getDistantChatStatus(const RsGxsId& gxs_id,uint32_t& status, RsGxsId *from_gxs_id=NULL) ; - virtual bool closeDistantChatConnexion(const RsGxsId &pid) ; + virtual bool initiateDistantChatConnexion(const RsGxsId& to_gxs_id, const RsGxsId& from_gxs_id, DistantChatPeerId &pid, uint32_t& error_code) ; + virtual bool getDistantChatStatus(const DistantChatPeerId& gxs_id,DistantChatPeerInfo& info); + virtual bool closeDistantChatConnexion(const DistantChatPeerId &pid) ; private: diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index c0e7697fa..1155472e7 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -56,6 +56,8 @@ #include #include +#include + #define ENABLE_GROUTER #if (defined(__unix__) || defined(unix)) && !defined(USG) @@ -1472,13 +1474,16 @@ int RsServer::StartupRetroShare() pqih -> addService(tr,true); pqih -> addService(ftserver,true); + p3GxsTunnelService *gxs_tunnels = new p3GxsTunnelService() ; + rsGxsTunnels = gxs_tunnels; + rsDisc = mDisc; rsMsgs = new p3Msgs(msgSrv, chatSrv); // connect components to turtle router. ftserver->connectToTurtleRouter(tr) ; - chatSrv->connectToTurtleRouter(tr) ; + chatSrv->connectToxsTunnelService(gxs_tunnels) ; gr->connectToTurtleRouter(tr) ; #ifdef ENABLE_GROUTER msgSrv->connectToGlobalRouter(gr) ; @@ -1489,8 +1494,7 @@ int RsServer::StartupRetroShare() pqih -> addService(mDisc,true); pqih -> addService(msgSrv,true); pqih -> addService(chatSrv,true); - pqih -> addService(mStatusSrv,true); - + pqih -> addService(mStatusSrv,true); // set interfaces for plugins // diff --git a/retroshare-gui/src/gui/chat/ChatDialog.cpp b/retroshare-gui/src/gui/chat/ChatDialog.cpp index d1fb0bd47..894416f08 100644 --- a/retroshare-gui/src/gui/chat/ChatDialog.cpp +++ b/retroshare-gui/src/gui/chat/ChatDialog.cpp @@ -104,10 +104,9 @@ void ChatDialog::init(ChatId id, const QString &title) ChatLobbyDialog* cld = new ChatLobbyDialog(id.toLobbyId()); cld->init(); cd = cld; - } else if(id.isGxsId()) { - PopupDistantChatDialog* pdcd = new PopupDistantChatDialog(); - QString peer_name = pdcd->getPeerName(id) ; - pdcd->init(id.toGxsId(), tr("Talking to")+" "+peer_name) ; + } else if(id.isGxsTunnelId()) { + PopupDistantChatDialog* pdcd = new PopupDistantChatDialog(id.toGxsTunnelId()); + pdcd->init() ; cd = pdcd; } else { RsPeerDetails sslDetails; diff --git a/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp b/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp index a72c72bae..8f04d8df6 100644 --- a/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp +++ b/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp @@ -553,8 +553,9 @@ void ChatLobbyDialog::distantChatParticipant() rsMsgs->getIdentityForChatLobby(lobbyId, own_id); uint32_t error_code ; + RsGxsTunnelService::RsGxsTunnelId tunnel_id; - if(! rsMsgs->initiateDistantChatConnexion(gxs_id,own_id,error_code)) + if(! rsMsgs->initiateDistantChatConnexion(gxs_id,own_id,tunnel_id,error_code)) { QString error_str ; switch(error_code) diff --git a/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp b/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp index 334ab1b82..d454ff11e 100644 --- a/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp +++ b/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp @@ -43,9 +43,11 @@ PopupDistantChatDialog::~PopupDistantChatDialog() delete _update_timer ; } -PopupDistantChatDialog::PopupDistantChatDialog(QWidget *parent, Qt::WindowFlags flags) +PopupDistantChatDialog::PopupDistantChatDialog(const RsGxsTunnelService::RsGxsTunnelId& tunnel_id,QWidget *parent, Qt::WindowFlags flags) : PopupChatDialog(parent,flags) { + _tunnel_id = tunnel_id ; + _status_label = new QLabel ; _update_timer = new QTimer ; @@ -58,97 +60,89 @@ PopupDistantChatDialog::PopupDistantChatDialog(QWidget *parent, Qt::WindowFlags updateDisplay() ; } -void PopupDistantChatDialog::init(const RsGxsId &gxs_id,const QString & title) +void PopupDistantChatDialog::init() { - _pid = gxs_id ; - PopupChatDialog::init(ChatId(gxs_id), title) ; + RsGxsTunnelService::GxsTunnelInfo tinfo; + + if(!rsGxsTunnels->getDistantChatStatus(tunnel_id,tinfo)) + return ; + + PopupChatDialog::init(ChatId(tinfo.destination_gxs_id), title) ; - RsGxsId own_gxs_id ; - uint32_t status ; - - // do not use setOwnId, because we don't want the user to change the GXS avatar from the chat window + // Do not use setOwnId, because we don't want the user to change the GXS avatar from the chat window // it will not be transmitted. - if(rsMsgs->getDistantChatStatus(gxs_id,status,&own_gxs_id)) - ui.ownAvatarWidget->setId(ChatId(own_gxs_id)); + ui.ownAvatarWidget->setId(ChatId(tinfo.source_gxs_id)); } void PopupDistantChatDialog::updateDisplay() { - if(RsAutoUpdatePage::eventsLocked()) // we need to do that by end, because it's not possible to derive from both PopupChatDialog and RsAutoUpdatePage - return ; // which both derive from QObject. Signals-slot connexions won't work anymore. + if(RsAutoUpdatePage::eventsLocked()) // we need to do that by end, because it's not possible to derive from both PopupChatDialog and RsAutoUpdatePage + return ; // which both derive from QObject. Signals-slot connexions won't work anymore. - if(!isVisible()) - return ; + if(!isVisible()) + return ; - //std::cerr << "Checking tunnel..." ; - // make sure about the tunnel status - // - - uint32_t status= RS_DISTANT_CHAT_STATUS_UNKNOWN; - rsMsgs->getDistantChatStatus(_pid,status) ; + //std::cerr << "Checking tunnel..." ; + // make sure about the tunnel status + // - ui.avatarWidget->setId(ChatId(_pid)); + RsGxsTunnelService::GxsTunnelInfo tinfo; + rsMsgs->getDistantChatStatus(_tunnel_id,tinfo) ; + + ui.avatarWidget->setId(ChatId(tinfo.destination_gxs_id)); QString msg; - switch(status) - { - case RS_DISTANT_CHAT_STATUS_UNKNOWN: //std::cerr << "Unknown hash. Error!" << std::endl; - _status_label->setPixmap(QPixmap(IMAGE_GRY_LED)) ; - msg = tr("Hash Error. No tunnel."); - _status_label->setToolTip(msg) ; - getChatWidget()->updateStatusString("%1", msg, true); - getChatWidget()->blockSending(tr("Can't send message, because there is no tunnel.")); - setPeerStatus(RS_STATUS_OFFLINE) ; - break ; - case RS_DISTANT_CHAT_STATUS_REMOTELY_CLOSED: std::cerr << "Chat remotely closed. " << std::endl; - _status_label->setPixmap(QPixmap(IMAGE_RED_LED)) ; - _status_label->setToolTip(QObject::tr("Distant peer has closed the chat")) ; + switch(tinfo.tunnel_status) + { + case RsGxsTunnelService::RS_DISTANT_CHAT_STATUS_UNKNOWN: //std::cerr << "Unknown hash. Error!" << std::endl; + _status_label->setPixmap(QPixmap(IMAGE_GRY_LED)) ; + msg = tr("Hash Error. No tunnel."); + _status_label->setToolTip(msg) ; + getChatWidget()->updateStatusString("%1", msg, true); + getChatWidget()->blockSending(tr("Can't send message, because there is no tunnel.")); + setPeerStatus(RS_STATUS_OFFLINE) ; + break ; + case RsGxsTunnelService::RS_DISTANT_CHAT_STATUS_REMOTELY_CLOSED: std::cerr << "Chat remotely closed. " << std::endl; + _status_label->setPixmap(QPixmap(IMAGE_RED_LED)) ; + _status_label->setToolTip(QObject::tr("Distant peer has closed the chat")) ; - getChatWidget()->updateStatusString("%1", tr("The person you're talking to has deleted the secured chat tunnel. You may remove the chat window now."), true); - getChatWidget()->blockSending(tr("Can't send message, because the chat partner deleted the secure tunnel.")); - setPeerStatus(RS_STATUS_OFFLINE) ; + getChatWidget()->updateStatusString("%1", tr("The person you're talking to has deleted the secured chat tunnel. You may remove the chat window now."), true); + getChatWidget()->blockSending(tr("Can't send message, because the chat partner deleted the secure tunnel.")); + setPeerStatus(RS_STATUS_OFFLINE) ; - break ; - case RS_DISTANT_CHAT_STATUS_TUNNEL_DN: //std::cerr << "Tunnel asked. Waiting for reponse. " << std::endl; - _status_label->setPixmap(QPixmap(IMAGE_RED_LED)) ; - msg = QObject::tr("Tunnel is pending..."); - _status_label->setToolTip(msg) ; - getChatWidget()->updateStatusString("%1", msg, true); - getChatWidget()->blockSending(msg); - setPeerStatus(RS_STATUS_OFFLINE) ; - break ; - case RS_DISTANT_CHAT_STATUS_TUNNEL_OK: //std::cerr << "Tunnel is ok. " << std::endl; - _status_label->setPixmap(QPixmap(IMAGE_YEL_LED)) ; - msg = QObject::tr("Secured tunnel established. Waiting for ACK..."); - _status_label->setToolTip(msg) ; - getChatWidget()->updateStatusString("%1", msg, true); - getChatWidget()->blockSending(msg); - setPeerStatus(RS_STATUS_ONLINE) ; - break ; - case RS_DISTANT_CHAT_STATUS_CAN_TALK: //std::cerr << "Tunnel is ok and data is transmitted." << std::endl; - _status_label->setPixmap(QPixmap(IMAGE_GRN_LED)) ; - msg = QObject::tr("Secured tunnel is working. You can talk!"); - _status_label->setToolTip(msg) ; - getChatWidget()->unblockSending(); - setPeerStatus(RS_STATUS_ONLINE) ; - break ; - } + break ; + case RsGxsTunnelService::RS_DISTANT_CHAT_STATUS_TUNNEL_DN: //std::cerr << "Tunnel asked. Waiting for reponse. " << std::endl; + _status_label->setPixmap(QPixmap(IMAGE_RED_LED)) ; + msg = QObject::tr("Tunnel is pending..."); + _status_label->setToolTip(msg) ; + getChatWidget()->updateStatusString("%1", msg, true); + getChatWidget()->blockSending(msg); + setPeerStatus(RS_STATUS_OFFLINE) ; + break ; + case RsGxsTunnelService::RS_DISTANT_CHAT_STATUS_CAN_TALK: //std::cerr << "Tunnel is ok and data is transmitted." << std::endl; + _status_label->setPixmap(QPixmap(IMAGE_GRN_LED)) ; + msg = QObject::tr("Secured tunnel is working. You can talk!"); + _status_label->setToolTip(msg) ; + getChatWidget()->unblockSending(); + setPeerStatus(RS_STATUS_ONLINE) ; + break ; + } } void PopupDistantChatDialog::closeEvent(QCloseEvent *e) { - //std::cerr << "Closing window => closing distant chat for hash " << _pid << std::endl; + //std::cerr << "Closing window => closing distant chat for hash " << _pid << std::endl; - uint32_t status= RS_DISTANT_CHAT_STATUS_UNKNOWN; - rsMsgs->getDistantChatStatus(_pid,status) ; + uint32_t status= RS_DISTANT_CHAT_STATUS_UNKNOWN; + rsMsgs->getDistantChatStatus(_pid,status) ; if(status != RS_DISTANT_CHAT_STATUS_REMOTELY_CLOSED) { QString msg = tr("Closing this window will end the conversation, notify the peer and remove the encrypted tunnel.") ; if(QMessageBox::Ok == QMessageBox::critical(NULL,tr("Kill the tunnel?"),msg, QMessageBox::Ok | QMessageBox::Cancel)) - rsMsgs->closeDistantChatConnexion(_pid) ; + rsMsgs->closeDistantChatConnexion(_tunnel_id) ; else { e->ignore() ; @@ -163,23 +157,26 @@ void PopupDistantChatDialog::closeEvent(QCloseEvent *e) QString PopupDistantChatDialog::getPeerName(const ChatId &id) const { + RsGxsTunnelService::GxsTunnelInfo tinfo; + + rsMsgs->getDistantChatStatus(_tunnel_id,tinfo) ; + RsIdentityDetails details ; - if(rsIdentity->getIdDetails(id.toGxsId(),details)) + if(rsIdentity->getIdDetails(destination_gxs_id,details)) return QString::fromUtf8( details.mNickname.c_str() ) ; else - return QString::fromStdString(id.toGxsId().toStdString()) ; + return QString::fromStdString(destination_gxs_id.toStdString()) ; } QString PopupDistantChatDialog::getOwnName() const { - uint32_t status= RS_DISTANT_CHAT_STATUS_UNKNOWN; - RsGxsId from_gxs_id ; + RsGxsTunnelService::GxsTunnelInfo tinfo; - rsMsgs->getDistantChatStatus(_pid,status,&from_gxs_id) ; + rsMsgs->getDistantChatStatus(_tunnel_id,tinfo) ; RsIdentityDetails details ; - if(rsIdentity->getIdDetails(from_gxs_id,details)) + if(rsIdentity->getIdDetails(source_gxs_id,details)) return QString::fromUtf8( details.mNickname.c_str() ) ; else - return QString::fromStdString(from_gxs_id.toStdString()) ; + return QString::fromStdString(source_gxs_id.toStdString()) ; } diff --git a/retroshare-gui/src/gui/chat/PopupDistantChatDialog.h b/retroshare-gui/src/gui/chat/PopupDistantChatDialog.h index 62c17a5c0..0e0175399 100644 --- a/retroshare-gui/src/gui/chat/PopupDistantChatDialog.h +++ b/retroshare-gui/src/gui/chat/PopupDistantChatDialog.h @@ -22,6 +22,7 @@ #pragma once +#include #include "PopupChatDialog.h" class QTimer ; @@ -33,7 +34,7 @@ class PopupDistantChatDialog: public PopupChatDialog protected: /** Default constructor */ - PopupDistantChatDialog(QWidget *parent = 0, Qt::WindowFlags flags = 0); + PopupDistantChatDialog(const RsGxsTunnelService::RsGxsTunnelId &tunnel_id, QWidget *parent = 0, Qt::WindowFlags flags = 0); /** Default destructor */ virtual ~PopupDistantChatDialog(); @@ -48,7 +49,7 @@ class PopupDistantChatDialog: public PopupChatDialog private: QTimer *_update_timer ; - RsGxsId _pid ; + RsGxsTunnelService::RsGxsTunnelId _tunnel_id ; QLabel *_status_label ; friend class ChatDialog; From 6ca49a2d98ccdd59af76d9f778a9113d2b449ee0 Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 27 Nov 2015 23:37:39 -0500 Subject: [PATCH 11/26] fixed serialisation methods for GxsTunnel service --- libretroshare/src/chat/rschatitems.cc | 81 - libretroshare/src/gxstunnel/p3gxstunnel.cc | 2 +- .../src/gxstunnel/rsgxstunnelitems.cc | 1416 ++++------------- .../src/gxstunnel/rsgxstunnelitems.h | 33 +- libretroshare/src/retroshare/rsgxstunnel.h | 6 +- libretroshare/src/rsserver/p3face.h | 2 + libretroshare/src/rsserver/rsinit.cc | 6 +- 7 files changed, 298 insertions(+), 1248 deletions(-) diff --git a/libretroshare/src/chat/rschatitems.cc b/libretroshare/src/chat/rschatitems.cc index e44102bc4..1074eee1c 100644 --- a/libretroshare/src/chat/rschatitems.cc +++ b/libretroshare/src/chat/rschatitems.cc @@ -51,18 +51,6 @@ std::ostream& RsChatMsgItem::print(std::ostream &out, uint16_t indent) printRsItemEnd(out, "RsChatMsgItem", indent); return out; } -std::ostream& RsChatDHPublicKeyItem::print(std::ostream &out, uint16_t indent) -{ - printRsItemBase(out, "RsChatDHPublicKeyItem", indent); - uint16_t int_Indent = indent + 2; - - printIndent(out, int_Indent); - out << " Signature Key ID: " << signature.keyId << std::endl ; - out << " Public Key ID: " << gxs_key.keyId << std::endl ; - - printRsItemEnd(out, "RsChatMsgItem", indent); - return out; -} std::ostream& RsChatLobbyListItem::print(std::ostream &out, uint16_t indent) { @@ -277,7 +265,6 @@ RsItem *RsChatSerialiser::deserialise(void *data, uint32_t *pktsize) case RS_PKT_SUBTYPE_CHAT_LOBBY_LIST_REQUEST: return new RsChatLobbyListRequestItem(data,*pktsize) ; case RS_PKT_SUBTYPE_CHAT_LOBBY_LIST: return new RsChatLobbyListItem(data,*pktsize) ; case RS_PKT_SUBTYPE_CHAT_LOBBY_CONFIG: return new RsChatLobbyConfigItem(data,*pktsize) ; - case RS_PKT_SUBTYPE_DISTANT_CHAT_DH_PUBLIC_KEY: return new RsChatDHPublicKeyItem(data,*pktsize) ; default: std::cerr << "Unknown packet type in chat!" << std::endl ; return NULL ; @@ -437,17 +424,6 @@ uint32_t RsChatLobbyConfigItem::serial_size() return s; } -uint32_t RsChatDHPublicKeyItem::serial_size() -{ - uint32_t s = 8 ; // header - s += 4 ; // BN size - s += BN_num_bytes(public_key) ; // public_key - s += signature.TlvSize() ; // signature - s += gxs_key.TlvSize() ; // gxs_key - - return s ; -} - /*************************************************************************/ RsChatAvatarItem::~RsChatAvatarItem() @@ -459,41 +435,6 @@ RsChatAvatarItem::~RsChatAvatarItem() } } -bool RsChatDHPublicKeyItem::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); - - /* skip the header */ - offset += 8; - - uint32_t s = BN_num_bytes(public_key) ; - - ok &= setRawUInt32(data, tlvsize, &offset, s); - - BN_bn2bin(public_key,&((unsigned char *)data)[offset]) ; - offset += s ; - - ok &= signature.SetTlv(data, tlvsize, &offset); - ok &= gxs_key.SetTlv(data, tlvsize, &offset); - - if (offset != tlvsize) - { - ok = false; - std::cerr << "RsChatDHPublicKeyItem::serialiseItem() Size Error! offset=" << offset << ", tlvsize=" << tlvsize << std::endl; - } - return ok ; -} - /* serialise the data to the buffer */ bool RsChatMsgItem::serialise(void *data, uint32_t& pktsize) { @@ -995,28 +936,6 @@ bool RsChatLobbyConfigItem::serialise(void *data, uint32_t& pktsize) return ok; } -RsChatDHPublicKeyItem::RsChatDHPublicKeyItem(void *data,uint32_t /*size*/) - : RsChatItem(RS_PKT_SUBTYPE_DISTANT_CHAT_DH_PUBLIC_KEY) -{ - uint32_t offset = 8; // skip the header - uint32_t rssize = getRsItemSize(data); - bool ok = true ; - - uint32_t s=0 ; - /* get mandatory parts first */ - ok &= getRawUInt32(data, rssize, &offset, &s); - - public_key = BN_bin2bn(&((unsigned char *)data)[offset],s,NULL) ; - offset += s ; - - ok &= signature.GetTlv(data, rssize, &offset) ; - ok &= gxs_key.GetTlv(data, rssize, &offset) ; - - if (offset != rssize) - std::cerr << "RsChatDHPublicKeyItem::() Size error while deserializing." << std::endl ; - if (!ok) - std::cerr << "RsChatDHPublicKeyItem::() Unknown error while deserializing." << std::endl ; -} RsChatMsgItem::RsChatMsgItem(void *data,uint32_t /*size*/,uint8_t subtype) : RsChatItem(subtype) { diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.cc b/libretroshare/src/gxstunnel/p3gxstunnel.cc index b2c1fffae..831804fc9 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.cc +++ b/libretroshare/src/gxstunnel/p3gxstunnel.cc @@ -585,7 +585,7 @@ bool p3GxsTunnelService::handleEncryptedData(const uint8_t *data_bytes,uint32_t // Now try deserialise the decrypted data to make an RsItem out of it. // - citem = RsGxsTunnelSerialiser().deserialiseGxsTunnelItem(decrypted_data,&decrypted_size) ; + citem = dynamic_cast(RsGxsTunnelSerialiser().deserialise(decrypted_data,&decrypted_size)) ; delete[] decrypted_data ; diff --git a/libretroshare/src/gxstunnel/rsgxstunnelitems.cc b/libretroshare/src/gxstunnel/rsgxstunnelitems.cc index e08421120..15522c000 100644 --- a/libretroshare/src/gxstunnel/rsgxstunnelitems.cc +++ b/libretroshare/src/gxstunnel/rsgxstunnelitems.cc @@ -28,423 +28,120 @@ #include #include "serialiser/rsbaseserial.h" #include "serialiser/rstlvbase.h" +#include "util/rsprint.h" -#include "chat/rschatitems.h" +#include "gxstunnel/rsgxstunnelitems.h" -//#define CHAT_DEBUG 1 +//#define GXS_TUNNEL_ITEM_DEBUG 1 -std::ostream& RsChatMsgItem::print(std::ostream &out, uint16_t indent) +std::ostream& RsGxsTunnelDHPublicKeyItem::print(std::ostream &out, uint16_t indent) { - printRsItemBase(out, "RsChatMsgItem", indent); + printRsItemBase(out, "RsGxsTunnelDHPublicKeyItem", indent); uint16_t int_Indent = indent + 2; - printIndent(out, int_Indent); - out << "QblogMs " << chatFlags << std::endl; - - printIndent(out, int_Indent); - out << "sendTime: " << sendTime << " (" << time(NULL)-sendTime << " secs ago)" << std::endl; - - printIndent(out, int_Indent); - - std::string cnv_message(message.begin(), message.end()); - out << "msg: " << cnv_message << std::endl; - - printRsItemEnd(out, "RsChatMsgItem", indent); - return out; -} -std::ostream& RsChatDHPublicKeyItem::print(std::ostream &out, uint16_t indent) -{ - printRsItemBase(out, "RsChatDHPublicKeyItem", indent); - uint16_t int_Indent = indent + 2; printIndent(out, int_Indent); out << " Signature Key ID: " << signature.keyId << std::endl ; out << " Public Key ID: " << gxs_key.keyId << std::endl ; - printRsItemEnd(out, "RsChatMsgItem", indent); + printRsItemEnd(out, "RsGxsTunnelMsgItem", indent); return out; } -std::ostream& RsChatLobbyListItem::print(std::ostream &out, uint16_t indent) +std::ostream& RsGxsTunnelDataItem::print(std::ostream &out, uint16_t indent) { - printRsItemBase(out, "RsChatLobbyListItem", indent); - - for(uint32_t i=0;i50u)?"...":"") << std::endl ; - printIndent(out, int_Indent); - out << "lobby id: " << std::hex << lobby_id << std::dec << std::endl; - - printIndent(out, int_Indent); - out << "lobby name: " << lobby_name << std::endl; - - printIndent(out, int_Indent); - out << "lobby topic: " << lobby_topic << std::endl; - - printRsItemEnd(out, "RsChatLobbyInviteItem", indent); + printRsItemEnd(out, "RsGxsTunnelDataItem", indent); return out; } -std::ostream& RsPrivateChatMsgConfigItem::print(std::ostream &out, uint16_t indent) +std::ostream& RsGxsTunnelDataAckItem::print(std::ostream &out, uint16_t indent) { - printRsItemBase(out, "RsPrivateChatMsgConfigItem", indent); - uint16_t int_Indent = indent + 2; - - out << "peerId: " << configPeerId << std::endl; - - printIndent(out, int_Indent); - out << "QblogMs " << chatFlags << std::endl; - - printIndent(out, int_Indent); - out << "QblogMs " << configFlags << std::endl; - - printIndent(out, int_Indent); - out << "sendTime: " << sendTime << " (" << time(NULL)-sendTime << " secs ago)" << std::endl; - - printIndent(out, int_Indent); - - std::string cnv_message(message.begin(), message.end()); - out << "msg: " << cnv_message << std::endl; - - printRsItemEnd(out, "RsPrivateChatMsgConfigItem", indent); - return out; -} -std::ostream& RsPrivateChatDistantInviteConfigItem::print(std::ostream &out, uint16_t indent) -{ - printRsItemBase(out, "RsPrivateChatDistantInviteConfigItem", indent); + printRsItemBase(out, "RsGxsTunnelDataItem", indent); uint16_t int_Indent = indent + 2; printIndent(out, int_Indent); - out << "radix string: " << encrypted_radix64_string << std::endl; + out << " message id : " << std::hex << unique_item_counter << std::dec << 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; - - printIndent(out, int_Indent); - out << "flags: " << flags << std::endl; - - printRsItemEnd(out, "RsPrivateChatDistantInviteConfigItem", indent); + printRsItemEnd(out, "RsGxsTunnelDataAckItem", indent); return out; } -std::ostream& RsChatLobbyConfigItem::print(std::ostream &out, uint16_t indent) +std::ostream& RsGxsTunnelStatusItem::print(std::ostream &out, uint16_t indent) { - printRsItemBase(out, "RsChatLobbyConfigItem", indent); - uint16_t int_Indent = indent + 2; - - printIndent(out, int_Indent); - out << "lobby_Id: " << lobby_Id << std::endl; - out << "flags : " << flags << std::endl; - - printRsItemEnd(out, "RsChatLobbyConfigItem", indent); - return out; -} -std::ostream& RsChatStatusItem::print(std::ostream &out, uint16_t indent) -{ - printRsItemBase(out, "RsChatStatusItem", indent); + printRsItemBase(out, "RsGxsTunnelDataItem", indent); uint16_t int_Indent = indent + 2; - printIndent(out, int_Indent); - out << "Status string: " << status_string << std::endl; - out << "Flags : " << std::hex << flags << std::dec << std::endl; - printRsItemEnd(out, "RsChatStatusItem", indent); + printIndent(out, int_Indent); + out << " flags : " << std::hex << flags << std::dec << std::endl ; + + printRsItemEnd(out, "RsGxsTunnelStatusItem", indent); return out; } -std::ostream& RsChatAvatarItem::print(std::ostream &out, uint16_t indent) -{ - printRsItemBase(out, "RsChatAvatarItem", indent); - uint16_t int_Indent = indent + 2; - printIndent(out, int_Indent); - out << "Image size: " << image_size << std::endl; - printRsItemEnd(out, "RsChatStatusItem", indent); +/*************************************************************************/ - return out; -} RsGxsTunnelDHPublicKeyItem::~RsGxsTunnelDHPublicKeyItem() { BN_free(public_key) ; } -RsItem *RsChatSerialiser::deserialise(void *data, uint32_t *pktsize) -{ - uint32_t rstype = getRsItemId(data); - uint32_t rssize = getRsItemSize(data); -#ifdef CHAT_DEBUG - std::cerr << "deserializing packet..."<< std::endl ; +/*************************************************************************/ + +RsItem *RsGxsTunnelSerialiser::deserialise(void *data, uint32_t *pktsize) +{ + uint32_t rstype = getRsItemId(data); + uint32_t rssize = getRsItemSize(data); + +#ifdef GXS_TUNNEL_ITEM_DEBUG + std::cerr << "deserializing packet..."<< std::endl ; #endif - // look what we have... - if (*pktsize < rssize) /* check size */ - { -#ifdef CHAT_DEBUG - std::cerr << "chat deserialisation: not enough size: pktsize=" << *pktsize << ", rssize=" << rssize << std::endl ; -#endif - return NULL; /* not enough data */ - } - - /* set the packet length */ - *pktsize = rssize; - - /* ready to load */ - - if ((RS_PKT_VERSION_SERVICE != getRsItemVersion(rstype)) || (RS_SERVICE_TYPE_CHAT != getRsItemService(rstype))) - { -#ifdef CHAT_DEBUG - std::cerr << "chat deserialisation: wrong type !" << std::endl ; -#endif - return NULL; /* wrong type */ - } - - switch(getRsItemSubType(rstype)) - { - 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_SIGNED_MSG: return new RsChatLobbyMsgItem(data,*pktsize) ; - case RS_PKT_SUBTYPE_CHAT_LOBBY_INVITE: return new RsChatLobbyInviteItem(data,*pktsize) ; - case RS_PKT_SUBTYPE_CHAT_LOBBY_CHALLENGE: return new RsChatLobbyConnectChallengeItem(data,*pktsize) ; - case RS_PKT_SUBTYPE_CHAT_LOBBY_UNSUBSCRIBE: return new RsChatLobbyUnsubscribeItem(data,*pktsize) ; - case RS_PKT_SUBTYPE_CHAT_LOBBY_SIGNED_EVENT: return new RsChatLobbyEventItem(data,*pktsize) ; - case RS_PKT_SUBTYPE_CHAT_LOBBY_LIST_REQUEST: return new RsChatLobbyListRequestItem(data,*pktsize) ; - case RS_PKT_SUBTYPE_CHAT_LOBBY_LIST: return new RsChatLobbyListItem(data,*pktsize) ; - case RS_PKT_SUBTYPE_CHAT_LOBBY_CONFIG: return new RsChatLobbyConfigItem(data,*pktsize) ; - case RS_PKT_SUBTYPE_DISTANT_CHAT_DH_PUBLIC_KEY: return new RsChatDHPublicKeyItem(data,*pktsize) ; - default: - std::cerr << "Unknown packet type in chat!" << std::endl ; - return NULL ; - } -} - -uint32_t RsChatMsgItem::serial_size() -{ - uint32_t s = 8; /* header */ - s += 4; /* chatFlags */ - s += 4; /* sendTime */ - s += GetTlvStringSize(message); - - return s; -} - -uint32_t RsChatLobbyUnsubscribeItem::serial_size() -{ - uint32_t s = 8; /* header */ - s += 8; // challenge code - return s ; -} - - -uint32_t RsChatLobbyConnectChallengeItem::serial_size() -{ - uint32_t s = 8; /* header */ - s += 8; // challenge code - return s ; -} -uint32_t RsChatLobbyBouncingObject::serialized_size(bool include_signature) -{ - uint32_t s = 0 ; // no header! - s += 8 ; // lobby_id - s += 8 ; // msg_id - s += GetTlvStringSize(nick) ; // nick - - if(include_signature) - s += signature.TlvSize() ; // signature - - return s ; -} -uint32_t RsChatLobbyEventItem::signed_serial_size() -{ - uint32_t s = 8 ; // header - s += 1 ; // event_type - s += GetTlvStringSize(string1) ; // string1 - s += 4 ; // send time - s += RsChatLobbyBouncingObject::serialized_size(false) ; - - return s ; -} -uint32_t RsChatLobbyEventItem::serial_size() -{ - uint32_t s = 8 ; // header - s += 1 ; // event_type - s += GetTlvStringSize(string1) ; // string1 - s += 4 ; // send time - s += RsChatLobbyBouncingObject::serialized_size(true) ; - - return s ; -} -uint32_t RsChatLobbyListRequestItem::serial_size() -{ - uint32_t s = 8 ; // header - return s ; -} -uint32_t RsChatLobbyListItem::serial_size() -{ - uint32_t s = 8 ; // header - s += 4 ; // number of elements in the vectors - - for(uint32_t i=0;ipublic_key = BN_bin2bn(&((unsigned char *)data)[offset],s,NULL) ; + offset += s ; + + ok &= item->signature.GetTlv(data, rssize, &offset) ; + ok &= item->gxs_key.GetTlv(data, rssize, &offset) ; -#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 ; + { + std::cerr << "RsGxsTunnelDHPublicKeyItem::() Size error while deserializing." << std::endl ; + delete item ; + return NULL ; + } if (!ok) - std::cerr << "Unknown error while deserializing." << std::endl ; + { + std::cerr << "RsGxsTunnelDHPublicKeyItem::() Unknown error while deserializing." << std::endl ; + delete item ; + return NULL ; + } + + return item ; } -/* set data from RsChatMsgItem to RsPrivateChatMsgConfigItem */ -void RsPrivateChatMsgConfigItem::set(RsChatMsgItem *ci, const RsPeerId& /*peerId*/, uint32_t confFlags) +RsGxsTunnelDataItem *deserialise_RsGxsTunnelDataItem(void *dat,uint32_t size) { - PeerId(ci->PeerId()); - configPeerId = ci->PeerId(); - chatFlags = ci->chatFlags; - configFlags = confFlags; - sendTime = ci->sendTime; - message = ci->message; - recvTime = ci->recvTime; + uint32_t offset = 8; // skip the header + uint32_t rssize = getRsItemSize(dat); + bool ok = true ; + + RsGxsTunnelDataItem *item = new RsGxsTunnelDataItem(); + + /* get mandatory parts first */ + + ok &= getRawUInt64(dat, rssize, &offset, &item->unique_item_counter); + ok &= getRawUInt32(dat, rssize, &offset, &item->flags); + ok &= getRawUInt32(dat, rssize, &offset, &item->service_id); + ok &= getRawUInt32(dat, rssize, &offset, &item->data_size); + + if(offset + item->data_size <= size) + { + item->data = (unsigned char*)malloc(item->data_size) ; + + if(dat == NULL) + { + delete item ; + return NULL ; + } + + memcpy(item->data,&((uint8_t*)dat)[offset],item->data_size) ; + offset += item->data_size ; + } + else + ok = false ; + + + if (offset != rssize) + { + std::cerr << "RsGxsTunnelDHPublicKeyItem::() Size error while deserializing." << std::endl ; + delete item ; + return NULL ; + } + if (!ok) + { + std::cerr << "RsGxsTunnelDHPublicKeyItem::() Unknown error while deserializing." << std::endl ; + delete item ; + return NULL ; + } + + return item ; } -/* get data from RsPrivateChatMsgConfigItem to RsChatMsgItem */ -void RsPrivateChatMsgConfigItem::get(RsChatMsgItem *ci) +RsGxsTunnelDataAckItem *deserialise_RsGxsTunnelDataAckItem(void *dat,uint32_t /* size */) { - ci->PeerId(configPeerId); - ci->chatFlags = chatFlags; - //configFlags not used - ci->sendTime = sendTime; - ci->message = message; - ci->recvTime = recvTime; + uint32_t offset = 8; // skip the header + uint32_t rssize = getRsItemSize(dat); + bool ok = true ; + + RsGxsTunnelDataAckItem *item = new RsGxsTunnelDataAckItem(); + + /* get mandatory parts first */ + + ok &= getRawUInt64(dat, rssize, &offset, &item->unique_item_counter); + + if (offset != rssize) + { + std::cerr << "RsGxsTunnelDHPublicKeyItem::() Size error while deserializing." << std::endl ; + delete item ; + return NULL ; + } + if (!ok) + { + std::cerr << "RsGxsTunnelDHPublicKeyItem::() Unknown error while deserializing." << std::endl ; + delete item ; + return NULL ; + } + + return item ; } -RsChatStatusItem::RsChatStatusItem(void *data,uint32_t /*size*/) - : RsChatItem(RS_PKT_SUBTYPE_CHAT_STATUS) +RsGxsTunnelStatusItem *deserialise_RsGxsTunnelStatusItem(void *dat,uint32_t size) { - uint32_t offset = 8; // skip the header - uint32_t rssize = getRsItemSize(data); - bool ok = true ; + uint32_t offset = 8; // skip the header + uint32_t rssize = getRsItemSize(dat); + bool ok = true ; -#ifdef CHAT_DEBUG - std::cerr << "Building new chat status item." << std::endl ; -#endif - /* get mandatory parts first */ - ok &= getRawUInt32(data, rssize, &offset, &flags); - ok &= GetTlvString(data, rssize, &offset,TLV_TYPE_STR_MSG, status_string); + RsGxsTunnelStatusItem *item = new RsGxsTunnelStatusItem(); - if (offset != rssize) - std::cerr << "Size error while deserializing." << std::endl ; - if (!ok) - std::cerr << "Unknown error while deserializing." << std::endl ; -} + /* get mandatory parts first */ -RsChatAvatarItem::RsChatAvatarItem(void *data,uint32_t /*size*/) - : RsChatItem(RS_PKT_SUBTYPE_CHAT_AVATAR) -{ - uint32_t offset = 8; // skip the header - uint32_t rssize = getRsItemSize(data); - bool ok = true ; + ok &= getRawUInt32(dat, rssize, &offset, &item->flags); -#ifdef CHAT_DEBUG - std::cerr << "Building new chat status item." << std::endl ; -#endif - /* get mandatory parts first */ - ok &= getRawUInt32(data, rssize, &offset,&image_size); + if (offset != rssize) + { + std::cerr << "RsGxsTunnelDHPublicKeyItem::() Size error while deserializing." << std::endl ; + delete item ; + return NULL ; + } + if (!ok) + { + std::cerr << "RsGxsTunnelDHPublicKeyItem::() Unknown error while deserializing." << std::endl ; + delete item ; + return NULL ; + } - // ensure invalid image length does not overflow data - if( (offset + image_size) <= rssize){ - image_data = new unsigned char[image_size] ; - memcpy(image_data,(void*)((unsigned char*)data+offset),image_size) ; - offset += image_size ; - }else{ - ok = false; - std::cerr << "offset+image_size exceeds rssize" << std::endl; - } - - if (offset != rssize) - std::cerr << "Size error while deserializing." << std::endl ; - if (!ok) - std::cerr << "Unknown error while deserializing." << std::endl ; + return item ; } + + + + + + + + + + + + + + diff --git a/libretroshare/src/gxstunnel/rsgxstunnelitems.h b/libretroshare/src/gxstunnel/rsgxstunnelitems.h index 8aea07f67..a5bd1d7b4 100644 --- a/libretroshare/src/gxstunnel/rsgxstunnelitems.h +++ b/libretroshare/src/gxstunnel/rsgxstunnelitems.h @@ -25,6 +25,8 @@ #pragma once +#include + #include "retroshare/rstypes.h" #include "serialiser/rstlvkeys.h" #include "serialiser/rsserviceids.h" @@ -71,8 +73,8 @@ class RsGxsTunnelItem: public RsItem class RsGxsTunnelDataItem: public RsGxsTunnelItem { public: - RsGxsTunnelDataItem() :RsGxsTunnelItem(RS_PKT_SUBTYPE_GXS_TUNNEL_DATA) {} - RsGxsTunnelDataItem(uint8_t subtype) :RsGxsTunnelItem(subtype) {} + RsGxsTunnelDataItem() :RsGxsTunnelItem(RS_PKT_SUBTYPE_GXS_TUNNEL_DATA) { data=NULL ;data_size=0; } + RsGxsTunnelDataItem(uint8_t subtype) :RsGxsTunnelItem(subtype) { data=NULL ;data_size=0; } virtual ~RsGxsTunnelDataItem() {} virtual void clear() {} @@ -154,17 +156,22 @@ class RsGxsTunnelDHPublicKeyItem: public RsGxsTunnelItem class RsGxsTunnelSerialiser: public RsSerialType { - public: - RsGxsTunnelSerialiser() :RsSerialType(RS_PKT_VERSION_SERVICE, RS_SERVICE_TYPE_GXS_TUNNEL) {} +public: + RsGxsTunnelSerialiser() :RsSerialType(RS_PKT_VERSION_SERVICE, RS_SERVICE_TYPE_GXS_TUNNEL) {} - virtual uint32_t size (RsItem *item) - { - return static_cast(item)->serial_size() ; - } - virtual bool serialise(RsItem *item, void *data, uint32_t *size) - { - return static_cast(item)->serialise(data,*size) ; - } - virtual RsGxsTunnelItem *deserialiseGxsTunnelItem(void *data, uint32_t *size) ; + virtual uint32_t size (RsItem *item) + { + return static_cast(item)->serial_size() ; + } + virtual bool serialise(RsItem *item, void *data, uint32_t *size) + { + return static_cast(item)->serialise(data,*size) ; + } + RsItem *deserialise(void *data, uint32_t *pktsize); +private: + static RsGxsTunnelDataAckItem *deserialise_RsGxsTunnelDataAckItem (void *data, uint32_t size) ; + static RsGxsTunnelDataItem *deserialise_RsGxsTunnelDataItem (void *data, uint32_t size) ; + static RsGxsTunnelStatusItem *deserialise_RsGxsTunnelStatusItem (void *data, uint32_t size) ; + static RsGxsTunnelDHPublicKeyItem *deserialise_RsGxsTunnelDHPublicKeyItem(void *data, uint32_t size) ; }; diff --git a/libretroshare/src/retroshare/rsgxstunnel.h b/libretroshare/src/retroshare/rsgxstunnel.h index f7cdc708f..13df25f56 100644 --- a/libretroshare/src/retroshare/rsgxstunnel.h +++ b/libretroshare/src/retroshare/rsgxstunnel.h @@ -85,8 +85,8 @@ public: // Debugging info // //===================================================// - virtual bool getGxsTunnelsInfo(std::vector& infos) =0; - virtual bool getGxsTunnelInfo(const RsGxsTunnelId& tunnel_id,GxsTunnelInfo& info) =0; + //virtual bool getGxsTunnelsInfo(std::vector& infos) =0; + //virtual bool getGxsTunnelInfo(const RsGxsTunnelId& tunnel_id,GxsTunnelInfo& info) =0; // retrieve the routing probabilities @@ -108,7 +108,7 @@ public: // Data is sent through the established tunnel, possibly multiple times, until reception is acknowledged. If the tunnel does not exist, the item is rejected and // an error is issued. In any case, the memory ownership of the data is *not* transferred to the tunnel service, so the client should delete it afterwards, if needed. - virtual bool sendData(const RsGxsTunnelId tunnel_id, uint32_t client_service_id, const uint8_t *data, uint32_t data_size) =0; + virtual bool sendData(const RsGxsTunnelId& tunnel_id, uint32_t client_service_id, const uint8_t *data, uint32_t data_size) =0; // Removes any established tunnel to this GXS id. This makes the tunnel refuse further data, but the tunnel will be however kept alive // until all pending data is flushed. All clients attached to the tunnel will be notified that the tunnel gets closed. diff --git a/libretroshare/src/rsserver/p3face.h b/libretroshare/src/rsserver/p3face.h index 910434309..23efa5866 100644 --- a/libretroshare/src/rsserver/p3face.h +++ b/libretroshare/src/rsserver/p3face.h @@ -39,6 +39,7 @@ #include "util/rsthreads.h" #include "chat/p3chatservice.h" +#include "gxstunnel/p3gxstunnel.h" #include "services/p3msgservice.h" #include "services/p3statusservice.h" @@ -160,6 +161,7 @@ class RsServer: public RsControl, public RsTickingThread p3MsgService *msgSrv; p3ChatService *chatSrv; p3StatusService *mStatusSrv; + p3GxsTunnelService *mGxsTunnels; // This list contains all threaded services. It will be used to shut them down properly. diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index 1155472e7..f2f775649 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -1474,8 +1474,8 @@ int RsServer::StartupRetroShare() pqih -> addService(tr,true); pqih -> addService(ftserver,true); - p3GxsTunnelService *gxs_tunnels = new p3GxsTunnelService() ; - rsGxsTunnels = gxs_tunnels; + mGxsTunnels = new p3GxsTunnelService(mGxsIdService) ; + rsGxsTunnel = mGxsTunnels; rsDisc = mDisc; rsMsgs = new p3Msgs(msgSrv, chatSrv); @@ -1483,7 +1483,7 @@ int RsServer::StartupRetroShare() // connect components to turtle router. ftserver->connectToTurtleRouter(tr) ; - chatSrv->connectToxsTunnelService(gxs_tunnels) ; + chatSrv->connectToGxsTunnelService(mGxsTunnels) ; gr->connectToTurtleRouter(tr) ; #ifdef ENABLE_GROUTER msgSrv->connectToGlobalRouter(gr) ; From a29f15ae32f07f1851ddc1dfd84d2f2a0daf63ef Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 28 Nov 2015 14:55:56 -0500 Subject: [PATCH 12/26] fixed compilation, added missing methods for new distant chat --- libretroshare/src/chat/distantchat.cc | 28 ++++++++++- libretroshare/src/chat/distantchat.h | 5 +- libretroshare/src/chat/p3chatservice.cc | 10 ++-- libretroshare/src/gxstunnel/p3gxstunnel.cc | 43 +++++++++++++++++ libretroshare/src/gxstunnel/p3gxstunnel.h | 1 + .../src/gxstunnel/rsgxstunnelitems.cc | 8 ++-- libretroshare/src/retroshare/rsgxstunnel.h | 2 +- retroshare-gui/src/gui/Identity/IdDialog.cpp | 3 +- retroshare-gui/src/gui/chat/ChatDialog.cpp | 13 ++++-- .../src/gui/chat/ChatLobbyDialog.cpp | 2 +- .../src/gui/chat/PopupDistantChatDialog.cpp | 46 ++++++++++--------- .../src/gui/chat/PopupDistantChatDialog.h | 6 +-- .../src/gui/common/AvatarWidget.cpp | 3 +- 13 files changed, 124 insertions(+), 46 deletions(-) diff --git a/libretroshare/src/chat/distantchat.cc b/libretroshare/src/chat/distantchat.cc index b4891474d..70d3cc140 100644 --- a/libretroshare/src/chat/distantchat.cc +++ b/libretroshare/src/chat/distantchat.cc @@ -97,7 +97,7 @@ bool DistantChatService::handleOutgoingItem(RsChatItem *item) void DistantChatService::handleRecvChatStatusItem(RsChatStatusItem *cs) { if(cs->flags & RS_CHAT_FLAG_CLOSING_DISTANT_CONNECTION) - markDistantChatAsClosed(RsGxsId(cs->PeerId())) ; + markDistantChatAsClosed(DistantChatPeerId(cs->PeerId())) ; // nothing more to do, because the decryption routing will update the last_contact time when decrypting. @@ -105,6 +105,30 @@ void DistantChatService::handleRecvChatStatusItem(RsChatStatusItem *cs) std::cerr << "DistantChatService::handleRecvChatStatusItem(): received keep alive packet for inactive chat! peerId=" << cs->PeerId() << std::endl; } +void DistantChatService::notifyTunnelStatus(const RsGxsTunnelService::RsGxsTunnelId &tunnel_id, uint32_t tunnel_status) +{ + std::cerr << "DistantChatService::notifyTunnelStatus(): got notification " << std::hex << tunnel_status << std::dec << " for tunnel " << tunnel_id << std::endl; +#warning do something here +} + +void DistantChatService::receiveData(const RsGxsTunnelService::RsGxsTunnelId &tunnel_id, unsigned char *data, uint32_t data_size) +{ + std::cerr << "DistantChatService::receiveData(): got data of size " << data_size << " for tunnel " << tunnel_id << std::endl; +#warning do something here +} + +void DistantChatService::markDistantChatAsClosed(const DistantChatPeerId& dcpid) +{ + mGxsTunnels->closeExistingTunnel(RsGxsTunnelService::RsGxsTunnelId(dcpid)) ; + + RS_STACK_MUTEX(mDistantChatMtx) ; + + std::map::iterator it = mDistantChatContacts.find(dcpid) ; + + if(it != mDistantChatContacts.end()) + mDistantChatContacts.erase(it) ; +} + bool DistantChatService::initiateDistantChatConnexion(const RsGxsId& to_gxs_id, const RsGxsId& from_gxs_id, DistantChatPeerId& dcpid, uint32_t& error_code) { RsGxsTunnelId tunnel_id ; @@ -130,7 +154,7 @@ bool DistantChatService::getDistantChatStatus(const DistantChatPeerId& tunnel_id RsGxsTunnelService::GxsTunnelInfo tinfo ; - if(!mGxsTunnels->getGxsTunnelInfo(RsGxsTunnelId(tunnel_id),tinfo)) + if(!mGxsTunnels->getTunnelInfo(RsGxsTunnelId(tunnel_id),tinfo)) return false; cinfo.to_id = tinfo.destination_gxs_id; diff --git a/libretroshare/src/chat/distantchat.h b/libretroshare/src/chat/distantchat.h index cee527fdb..b13a0aa7e 100644 --- a/libretroshare/src/chat/distantchat.h +++ b/libretroshare/src/chat/distantchat.h @@ -44,6 +44,8 @@ public: mGxsTunnels = NULL ; } + // Overloaded methods from RsGxsTunnelClientService + virtual void connectToGxsTunnelService(RsGxsTunnelService *tunnel_service) ; // Creates the invite if the public key of the distant peer is available. @@ -79,8 +81,7 @@ private: // Utility functions. - void markDistantChatAsClosed(const RsGxsId &gxs_id) ; - void startClientDistantChatConnection(const RsGxsId &to_gxs_id,const RsGxsId& from_gxs_id) ; + void markDistantChatAsClosed(const DistantChatPeerId& dcpid) ; RsGxsTunnelService *mGxsTunnels ; diff --git a/libretroshare/src/chat/p3chatservice.cc b/libretroshare/src/chat/p3chatservice.cc index 9e014432b..f7a8050b5 100644 --- a/libretroshare/src/chat/p3chatservice.cc +++ b/libretroshare/src/chat/p3chatservice.cc @@ -500,11 +500,11 @@ void p3ChatService::handleIncomingItem(RsItem *item) return ; // don't delete! It's handled by handleRecvChatMsgItem in some specific cases only. } - if(DistantChatService::handleRecvItem(dynamic_cast(item))) - { - delete item ; - return ; - } +// if(DistantChatService::handleRecvItem(dynamic_cast(item))) +// { +// delete item ; +// return ; +// } if(DistributedChatService::handleRecvItem(dynamic_cast(item))) { diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.cc b/libretroshare/src/gxstunnel/p3gxstunnel.cc index 831804fc9..007cf4c6d 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.cc +++ b/libretroshare/src/gxstunnel/p3gxstunnel.cc @@ -58,6 +58,8 @@ static const uint32_t RS_GXS_TUNNEL_DELAY_BETWEEN_RESEND = 10 ; // re-send ever static const uint32_t GXS_TUNNEL_ENCRYPTION_HMAC_SIZE = SHA_DIGEST_LENGTH ; static const uint32_t GXS_TUNNEL_ENCRYPTION_IV_SIZE = 8 ; +RsGxsTunnelService *rsGxsTunnel = NULL ; + p3GxsTunnelService::p3GxsTunnelService(RsGixs *pids) : mGixs(pids), mGxsTunnelMtx("GXS tunnel") { @@ -73,6 +75,22 @@ void p3GxsTunnelService::connectToTurtleRouter(p3turtle *tr) tr->registerTunnelService(this) ; } +bool p3GxsTunnelService::registerClientService(uint32_t service_id,RsGxsTunnelService::RsGxsTunnelClientService *service) +{ + RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + + if(mRegisteredServices.find(service_id) != mRegisteredServices.end()) + { + std::cerr << "(EE) p3GxsTunnelService::registerClientService(): trying to register client " << std::hex << service_id << std::dec << ", which is already registered!" << std::endl; + return false; + } + + std::cerr << "p3GxsTunnelService::registerClientService(): registering client service " << std::hex << service_id << std::dec << std::endl; + + mRegisteredServices[service_id] = service ; + return true ; +} + void p3GxsTunnelService::flush() { // Flush pending DH items. This is a higher priority, so we deal with them first. @@ -1193,6 +1211,31 @@ RsGxsId p3GxsTunnelService::destinationGxsIdFromHash(const TurtleFileHash& sum) return RsGxsId(sum.toByteArray());// takes the first 16 bytes } +bool p3GxsTunnelService::getTunnelInfo(const RsGxsTunnelId& tunnel_id,GxsTunnelInfo& info) +{ + RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + + std::map::const_iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; + + if(it == _gxs_tunnel_contacts.end()) + return false ; + + info.destination_gxs_id = it->second.to_gxs_id; + info.source_gxs_id = it->second.own_gxs_id; + info.tunnel_status = it->second.status; +#warning data missing here + info.total_size_sent = 0; + info.total_size_received= 0; + + // Data packets + + info.pending_data_packets = 0; + info.total_data_packets_sent=0 ; + info.total_data_packets_received=0 ; + + return true ; +} + bool p3GxsTunnelService::getTunnelStatus(const RsGxsTunnelId& tunnel_id,uint32_t& status) { RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.h b/libretroshare/src/gxstunnel/p3gxstunnel.h index fa519fc84..16a1d2e8b 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.h +++ b/libretroshare/src/gxstunnel/p3gxstunnel.h @@ -126,6 +126,7 @@ public: virtual bool closeExistingTunnel(const RsGxsTunnelId &tunnel_id) ; virtual bool getTunnelStatus(const RsGxsTunnelId& tunnel_id,uint32_t &status); + virtual bool getTunnelInfo(const RsGxsTunnelId& tunnel_id,GxsTunnelInfo& info); virtual bool sendData(const RsGxsTunnelId& tunnel_id,uint32_t service_id,const uint8_t *data,uint32_t size) ; virtual bool registerClientService(uint32_t service_id,RsGxsTunnelClientService *service) ; diff --git a/libretroshare/src/gxstunnel/rsgxstunnelitems.cc b/libretroshare/src/gxstunnel/rsgxstunnelitems.cc index 15522c000..ed8a7c472 100644 --- a/libretroshare/src/gxstunnel/rsgxstunnelitems.cc +++ b/libretroshare/src/gxstunnel/rsgxstunnelitems.cc @@ -333,7 +333,7 @@ bool RsGxsTunnelDataAckItem::serialise(void *data, uint32_t& pktsize) /*************************************************************************/ -RsGxsTunnelDHPublicKeyItem *deserialise_RsGxsTunnelDHPublicKeyItem(void *data,uint32_t /*size*/) +RsGxsTunnelDHPublicKeyItem *RsGxsTunnelSerialiser::deserialise_RsGxsTunnelDHPublicKeyItem(void *data,uint32_t /*size*/) { uint32_t offset = 8; // skip the header uint32_t rssize = getRsItemSize(data); @@ -367,7 +367,7 @@ RsGxsTunnelDHPublicKeyItem *deserialise_RsGxsTunnelDHPublicKeyItem(void *data,ui return item ; } -RsGxsTunnelDataItem *deserialise_RsGxsTunnelDataItem(void *dat,uint32_t size) +RsGxsTunnelDataItem *RsGxsTunnelSerialiser::deserialise_RsGxsTunnelDataItem(void *dat,uint32_t size) { uint32_t offset = 8; // skip the header uint32_t rssize = getRsItemSize(dat); @@ -415,7 +415,7 @@ RsGxsTunnelDataItem *deserialise_RsGxsTunnelDataItem(void *dat,uint32_t size) return item ; } -RsGxsTunnelDataAckItem *deserialise_RsGxsTunnelDataAckItem(void *dat,uint32_t /* size */) +RsGxsTunnelDataAckItem *RsGxsTunnelSerialiser::deserialise_RsGxsTunnelDataAckItem(void *dat,uint32_t /* size */) { uint32_t offset = 8; // skip the header uint32_t rssize = getRsItemSize(dat); @@ -443,7 +443,7 @@ RsGxsTunnelDataAckItem *deserialise_RsGxsTunnelDataAckItem(void *dat,uint32_t /* return item ; } -RsGxsTunnelStatusItem *deserialise_RsGxsTunnelStatusItem(void *dat,uint32_t size) +RsGxsTunnelStatusItem *RsGxsTunnelSerialiser::deserialise_RsGxsTunnelStatusItem(void *dat,uint32_t size) { uint32_t offset = 8; // skip the header uint32_t rssize = getRsItemSize(dat); diff --git a/libretroshare/src/retroshare/rsgxstunnel.h b/libretroshare/src/retroshare/rsgxstunnel.h index 13df25f56..90499758c 100644 --- a/libretroshare/src/retroshare/rsgxstunnel.h +++ b/libretroshare/src/retroshare/rsgxstunnel.h @@ -86,7 +86,7 @@ public: //===================================================// //virtual bool getGxsTunnelsInfo(std::vector& infos) =0; - //virtual bool getGxsTunnelInfo(const RsGxsTunnelId& tunnel_id,GxsTunnelInfo& info) =0; + virtual bool getTunnelInfo(const RsGxsTunnelId& tunnel_id,GxsTunnelInfo& info) =0; // retrieve the routing probabilities diff --git a/retroshare-gui/src/gui/Identity/IdDialog.cpp b/retroshare-gui/src/gui/Identity/IdDialog.cpp index 1189b2d37..b3535338c 100644 --- a/retroshare-gui/src/gui/Identity/IdDialog.cpp +++ b/retroshare-gui/src/gui/Identity/IdDialog.cpp @@ -1014,8 +1014,9 @@ void IdDialog::chatIdentity() RsGxsId from_gxs_id(action->data().toString().toStdString()); uint32_t error_code ; + DistantChatPeerId did ; - if(!rsMsgs->initiateDistantChatConnexion(RsGxsId(keyId), from_gxs_id, error_code)) + if(!rsMsgs->initiateDistantChatConnexion(RsGxsId(keyId), from_gxs_id, did, error_code)) QMessageBox::information(NULL, tr("Distant chat cannot work"), QString("%1 %2: %3").arg(tr("Distant chat refused with this person.")).arg(tr("Error code")).arg(error_code)) ; } diff --git a/retroshare-gui/src/gui/chat/ChatDialog.cpp b/retroshare-gui/src/gui/chat/ChatDialog.cpp index 894416f08..6175cb8ad 100644 --- a/retroshare-gui/src/gui/chat/ChatDialog.cpp +++ b/retroshare-gui/src/gui/chat/ChatDialog.cpp @@ -93,6 +93,7 @@ void ChatDialog::init(ChatId id, const QString &title) /* see if it already exists */ ChatDialog *cd = getExistingChat(id); + DistantChatPeerInfo pinfo ; if (cd == NULL) { @@ -104,11 +105,15 @@ void ChatDialog::init(ChatId id, const QString &title) ChatLobbyDialog* cld = new ChatLobbyDialog(id.toLobbyId()); cld->init(); cd = cld; - } else if(id.isGxsTunnelId()) { - PopupDistantChatDialog* pdcd = new PopupDistantChatDialog(id.toGxsTunnelId()); - pdcd->init() ; + } + else if(id.isPeerId() && rsMsgs->getDistantChatStatus(id.toPeerId(),pinfo)) + { + PopupDistantChatDialog* pdcd = new PopupDistantChatDialog(id.toPeerId()); + pdcd->init(pinfo.peer_id, QString("This is a distant chat")) ; cd = pdcd; - } else { + } + else + { RsPeerDetails sslDetails; if (rsPeers->getPeerDetails(id.toPeerId(), sslDetails)) { PopupChatDialog* pcd = new PopupChatDialog(); diff --git a/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp b/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp index 8f04d8df6..c4ea3c1cc 100644 --- a/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp +++ b/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp @@ -553,7 +553,7 @@ void ChatLobbyDialog::distantChatParticipant() rsMsgs->getIdentityForChatLobby(lobbyId, own_id); uint32_t error_code ; - RsGxsTunnelService::RsGxsTunnelId tunnel_id; + DistantChatPeerId tunnel_id; if(! rsMsgs->initiateDistantChatConnexion(gxs_id,own_id,tunnel_id,error_code)) { diff --git a/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp b/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp index d454ff11e..966946616 100644 --- a/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp +++ b/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp @@ -43,7 +43,7 @@ PopupDistantChatDialog::~PopupDistantChatDialog() delete _update_timer ; } -PopupDistantChatDialog::PopupDistantChatDialog(const RsGxsTunnelService::RsGxsTunnelId& tunnel_id,QWidget *parent, Qt::WindowFlags flags) +PopupDistantChatDialog::PopupDistantChatDialog(const DistantChatPeerId& tunnel_id,QWidget *parent, Qt::WindowFlags flags) : PopupChatDialog(parent,flags) { _tunnel_id = tunnel_id ; @@ -60,19 +60,20 @@ PopupDistantChatDialog::PopupDistantChatDialog(const RsGxsTunnelService::RsGxsTu updateDisplay() ; } -void PopupDistantChatDialog::init() +void PopupDistantChatDialog::init(const DistantChatPeerId &peer_id, const QString &title) { - RsGxsTunnelService::GxsTunnelInfo tinfo; + _tunnel_id = peer_id; + DistantChatPeerInfo tinfo; - if(!rsGxsTunnels->getDistantChatStatus(tunnel_id,tinfo)) + if(!rsMsgs->getDistantChatStatus(_tunnel_id,tinfo)) return ; - PopupChatDialog::init(ChatId(tinfo.destination_gxs_id), title) ; + PopupChatDialog::init(ChatId(tinfo.to_id), title) ; // Do not use setOwnId, because we don't want the user to change the GXS avatar from the chat window // it will not be transmitted. - ui.ownAvatarWidget->setId(ChatId(tinfo.source_gxs_id)); + ui.ownAvatarWidget->setId(ChatId(tinfo.own_id)); } void PopupDistantChatDialog::updateDisplay() @@ -87,15 +88,15 @@ void PopupDistantChatDialog::updateDisplay() // make sure about the tunnel status // - RsGxsTunnelService::GxsTunnelInfo tinfo; + DistantChatPeerInfo tinfo; rsMsgs->getDistantChatStatus(_tunnel_id,tinfo) ; - ui.avatarWidget->setId(ChatId(tinfo.destination_gxs_id)); + ui.avatarWidget->setId(ChatId(tinfo.to_id)); QString msg; - switch(tinfo.tunnel_status) + switch(tinfo.status) { - case RsGxsTunnelService::RS_DISTANT_CHAT_STATUS_UNKNOWN: //std::cerr << "Unknown hash. Error!" << std::endl; + case RS_DISTANT_CHAT_STATUS_UNKNOWN: //std::cerr << "Unknown hash. Error!" << std::endl; _status_label->setPixmap(QPixmap(IMAGE_GRY_LED)) ; msg = tr("Hash Error. No tunnel."); _status_label->setToolTip(msg) ; @@ -103,7 +104,7 @@ void PopupDistantChatDialog::updateDisplay() getChatWidget()->blockSending(tr("Can't send message, because there is no tunnel.")); setPeerStatus(RS_STATUS_OFFLINE) ; break ; - case RsGxsTunnelService::RS_DISTANT_CHAT_STATUS_REMOTELY_CLOSED: std::cerr << "Chat remotely closed. " << std::endl; + case RS_DISTANT_CHAT_STATUS_REMOTELY_CLOSED: std::cerr << "Chat remotely closed. " << std::endl; _status_label->setPixmap(QPixmap(IMAGE_RED_LED)) ; _status_label->setToolTip(QObject::tr("Distant peer has closed the chat")) ; @@ -112,7 +113,7 @@ void PopupDistantChatDialog::updateDisplay() setPeerStatus(RS_STATUS_OFFLINE) ; break ; - case RsGxsTunnelService::RS_DISTANT_CHAT_STATUS_TUNNEL_DN: //std::cerr << "Tunnel asked. Waiting for reponse. " << std::endl; + case RS_DISTANT_CHAT_STATUS_TUNNEL_DN: //std::cerr << "Tunnel asked. Waiting for reponse. " << std::endl; _status_label->setPixmap(QPixmap(IMAGE_RED_LED)) ; msg = QObject::tr("Tunnel is pending..."); _status_label->setToolTip(msg) ; @@ -120,7 +121,7 @@ void PopupDistantChatDialog::updateDisplay() getChatWidget()->blockSending(msg); setPeerStatus(RS_STATUS_OFFLINE) ; break ; - case RsGxsTunnelService::RS_DISTANT_CHAT_STATUS_CAN_TALK: //std::cerr << "Tunnel is ok and data is transmitted." << std::endl; + case RS_DISTANT_CHAT_STATUS_CAN_TALK: //std::cerr << "Tunnel is ok and data is transmitted." << std::endl; _status_label->setPixmap(QPixmap(IMAGE_GRN_LED)) ; msg = QObject::tr("Secured tunnel is working. You can talk!"); _status_label->setToolTip(msg) ; @@ -134,10 +135,11 @@ void PopupDistantChatDialog::closeEvent(QCloseEvent *e) { //std::cerr << "Closing window => closing distant chat for hash " << _pid << std::endl; - uint32_t status= RS_DISTANT_CHAT_STATUS_UNKNOWN; - rsMsgs->getDistantChatStatus(_pid,status) ; + DistantChatPeerInfo tinfo ; + + rsMsgs->getDistantChatStatus(_tunnel_id,tinfo) ; - if(status != RS_DISTANT_CHAT_STATUS_REMOTELY_CLOSED) + if(tinfo.status != RS_DISTANT_CHAT_STATUS_REMOTELY_CLOSED) { QString msg = tr("Closing this window will end the conversation, notify the peer and remove the encrypted tunnel.") ; @@ -157,26 +159,26 @@ void PopupDistantChatDialog::closeEvent(QCloseEvent *e) QString PopupDistantChatDialog::getPeerName(const ChatId &id) const { - RsGxsTunnelService::GxsTunnelInfo tinfo; + DistantChatPeerInfo tinfo; rsMsgs->getDistantChatStatus(_tunnel_id,tinfo) ; RsIdentityDetails details ; - if(rsIdentity->getIdDetails(destination_gxs_id,details)) + if(rsIdentity->getIdDetails(tinfo.to_id,details)) return QString::fromUtf8( details.mNickname.c_str() ) ; else - return QString::fromStdString(destination_gxs_id.toStdString()) ; + return QString::fromStdString(tinfo.to_id.toStdString()) ; } QString PopupDistantChatDialog::getOwnName() const { - RsGxsTunnelService::GxsTunnelInfo tinfo; + DistantChatPeerInfo tinfo; rsMsgs->getDistantChatStatus(_tunnel_id,tinfo) ; RsIdentityDetails details ; - if(rsIdentity->getIdDetails(source_gxs_id,details)) + if(rsIdentity->getIdDetails(tinfo.own_id,details)) return QString::fromUtf8( details.mNickname.c_str() ) ; else - return QString::fromStdString(source_gxs_id.toStdString()) ; + return QString::fromStdString(tinfo.own_id.toStdString()) ; } diff --git a/retroshare-gui/src/gui/chat/PopupDistantChatDialog.h b/retroshare-gui/src/gui/chat/PopupDistantChatDialog.h index 0e0175399..85a9144e4 100644 --- a/retroshare-gui/src/gui/chat/PopupDistantChatDialog.h +++ b/retroshare-gui/src/gui/chat/PopupDistantChatDialog.h @@ -34,11 +34,11 @@ class PopupDistantChatDialog: public PopupChatDialog protected: /** Default constructor */ - PopupDistantChatDialog(const RsGxsTunnelService::RsGxsTunnelId &tunnel_id, QWidget *parent = 0, Qt::WindowFlags flags = 0); + PopupDistantChatDialog(const DistantChatPeerId &tunnel_id, QWidget *parent = 0, Qt::WindowFlags flags = 0); /** Default destructor */ virtual ~PopupDistantChatDialog(); - virtual void init(const RsGxsId &gxs_id, const QString &title); + virtual void init(const DistantChatPeerId& peer_id, const QString &title); virtual void closeEvent(QCloseEvent *e) ; virtual QString getPeerName(const ChatId &id) const ; @@ -49,7 +49,7 @@ class PopupDistantChatDialog: public PopupChatDialog private: QTimer *_update_timer ; - RsGxsTunnelService::RsGxsTunnelId _tunnel_id ; + DistantChatPeerId _tunnel_id ; QLabel *_status_label ; friend class ChatDialog; diff --git a/retroshare-gui/src/gui/common/AvatarWidget.cpp b/retroshare-gui/src/gui/common/AvatarWidget.cpp index c8c5fe0d7..8a888c884 100644 --- a/retroshare-gui/src/gui/common/AvatarWidget.cpp +++ b/retroshare-gui/src/gui/common/AvatarWidget.cpp @@ -200,8 +200,9 @@ void AvatarWidget::refreshStatus() } else if(mId.isGxsId()) { - if(!rsMsgs->getDistantChatStatus(mId.toGxsId(),status)) +//if(!rsMsgs->getDistantChatStatus(mId.toGxsId(),status)) status = RS_STATUS_OFFLINE ; +#warning we need to do something clever here } else { From 6951d730a571297adb638e3fa4c44aabc473a61c Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 28 Nov 2015 18:02:57 -0500 Subject: [PATCH 13/26] debugging of GxsTunnel service - fixed transport layer --- libretroshare/src/gxstunnel/p3gxstunnel.cc | 77 ++++++++++++++++++- libretroshare/src/gxstunnel/p3gxstunnel.h | 10 ++- .../src/gxstunnel/rsgxstunnelitems.cc | 4 +- libretroshare/src/retroshare/rsplugin.h | 2 + libretroshare/src/rsserver/rsinit.cc | 4 + 5 files changed, 91 insertions(+), 6 deletions(-) diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.cc b/libretroshare/src/gxstunnel/p3gxstunnel.cc index 007cf4c6d..043869800 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.cc +++ b/libretroshare/src/gxstunnel/p3gxstunnel.cc @@ -58,6 +58,15 @@ static const uint32_t RS_GXS_TUNNEL_DELAY_BETWEEN_RESEND = 10 ; // re-send ever static const uint32_t GXS_TUNNEL_ENCRYPTION_HMAC_SIZE = SHA_DIGEST_LENGTH ; static const uint32_t GXS_TUNNEL_ENCRYPTION_IV_SIZE = 8 ; +static const uint32_t INTERVAL_BETWEEN_DEBUG_DUMP = 10 ; + +static std::string GXS_TUNNEL_APP_NAME = "GxsTunnels" ; + +static const uint8_t GXS_TUNNEL_APP_MAJOR_VERSION = 0x01 ; +static const uint8_t GXS_TUNNEL_APP_MINOR_VERSION = 0x00 ; +static const uint8_t GXS_TUNNEL_MIN_MAJOR_VERSION = 0x01 ; +static const uint8_t GXS_TUNNEL_MIN_MINOR_VERSION = 0x00 ; + RsGxsTunnelService *rsGxsTunnel = NULL ; p3GxsTunnelService::p3GxsTunnelService(RsGixs *pids) @@ -91,6 +100,31 @@ bool p3GxsTunnelService::registerClientService(uint32_t service_id,RsGxsTunnelSe return true ; } +int p3GxsTunnelService::tick() +{ + static time_t last_dump = 0 ; + std::cerr << "p3GxsTunnelService::tick()" << std::endl; + time_t now = time(NULL); + + if(now > last_dump + INTERVAL_BETWEEN_DEBUG_DUMP ) + { + last_dump = now ; + debug_dump() ; + } + + flush() ; +} + +RsServiceInfo p3GxsTunnelService::getServiceInfo() +{ + return RsServiceInfo(RS_SERVICE_TYPE_GXS_TUNNEL, + GXS_TUNNEL_APP_NAME, + GXS_TUNNEL_APP_MAJOR_VERSION, + GXS_TUNNEL_APP_MINOR_VERSION, + GXS_TUNNEL_MIN_MAJOR_VERSION, + GXS_TUNNEL_MIN_MINOR_VERSION); +} + void p3GxsTunnelService::flush() { // Flush pending DH items. This is a higher priority, so we deal with them first. @@ -342,7 +376,7 @@ void p3GxsTunnelService::addVirtualPeer(const TurtleFileHash& hash,const TurtleV } else // client side { - std::map::const_iterator it ; + std::map::const_iterator it = _gxs_tunnel_contacts.begin(); while(it != _gxs_tunnel_contacts.end() && it->second.hash != hash) ++it ; @@ -495,7 +529,8 @@ void p3GxsTunnelService::receiveTurtleData(RsTurtleGenericTunnelItem *gitem,cons // Now try deserialise the decrypted data to make an RsItem out of it. // - RsItem *citem = RsGxsTunnelSerialiser().deserialise(&((uint8_t*)item->data_bytes)[8],&item->data_size-8) ; + uint32_t pktsize = item->data_size-8; + RsItem *citem = RsGxsTunnelSerialiser().deserialise(&((uint8_t*)item->data_bytes)[8],&pktsize) ; if(citem == NULL) { @@ -1340,3 +1375,41 @@ void p3GxsTunnelService::markGxsTunnelAsClosed(const RsGxsTunnelId& tunnel_id) } } +void p3GxsTunnelService::debug_dump() +{ + RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + + time_t now = time(NULL) ; + + std::cerr << "p3GxsTunnelService::debug_dump()" << std::endl; + std::cerr << " Registered client services: " << std::endl; + + for(std::map::const_iterator it=mRegisteredServices.begin();it!=mRegisteredServices.end();++it) + std::cerr << std::hex << " " << it->first << " - " << (void*)it->second << std::dec << std::endl; + + std::cerr << " Active tunnels" << std::endl; + + for(std::map::const_iterator it=_gxs_tunnel_contacts.begin();it!=_gxs_tunnel_contacts.end();++it) + std::cerr << " tunnel_id=" << it->first << " vpid=" << it->second.virtual_peer_id << " status=" << it->second.status << " direction=" << it->second.direction << " last_contact=" << (now-it->second.last_contact) <<" secs ago. Last_keep_alive_sent:" << (now - it->second.last_keep_alive_sent) << " secs ago." << std::endl; + + std::cerr << " Virtual peers:" << std::endl; + + for(std::map::const_iterator it=_gxs_tunnel_virtual_peer_ids.begin();it!=_gxs_tunnel_virtual_peer_ids.end();++it) + std::cerr << " vpid=" << it->first << " to=" << it->second.gxs_id << " from=" << it->second.own_gxs_id << " tunnel_id=" << it->second.tunnel_id << " status=" << it->second.status << " direction=" << it->second.direction << " hash=" << it->second.hash << std::endl; +} + + + + + + + + + + + + + + + + diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.h b/libretroshare/src/gxstunnel/p3gxstunnel.h index 16a1d2e8b..9138f9f86 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.h +++ b/libretroshare/src/gxstunnel/p3gxstunnel.h @@ -107,13 +107,14 @@ #include #include +#include #include class RsGixs ; static const uint32_t GXS_TUNNEL_AES_KEY_SIZE = 16 ; -class p3GxsTunnelService: public RsGxsTunnelService, public RsTurtleClientService +class p3GxsTunnelService: public RsGxsTunnelService, public RsTurtleClientService, public p3Service { public: p3GxsTunnelService(RsGixs *pids) ; @@ -131,6 +132,11 @@ public: virtual bool registerClientService(uint32_t service_id,RsGxsTunnelClientService *service) ; + // derived from p3service + + virtual int tick(); + virtual RsServiceInfo getServiceInfo(); + private: void flush() ; virtual void handleIncomingItem(const RsGxsTunnelId &tunnel_id, RsGxsTunnelItem *) ; @@ -237,5 +243,7 @@ private: uint64_t global_item_counter ; std::map mRegisteredServices ; + + void debug_dump(); }; diff --git a/libretroshare/src/gxstunnel/rsgxstunnelitems.cc b/libretroshare/src/gxstunnel/rsgxstunnelitems.cc index ed8a7c472..055fb4ba0 100644 --- a/libretroshare/src/gxstunnel/rsgxstunnelitems.cc +++ b/libretroshare/src/gxstunnel/rsgxstunnelitems.cc @@ -32,7 +32,7 @@ #include "gxstunnel/rsgxstunnelitems.h" -//#define GXS_TUNNEL_ITEM_DEBUG 1 +#define GXS_TUNNEL_ITEM_DEBUG 1 std::ostream& RsGxsTunnelDHPublicKeyItem::print(std::ostream &out, uint16_t indent) { @@ -105,9 +105,7 @@ RsItem *RsGxsTunnelSerialiser::deserialise(void *data, uint32_t *pktsize) // look what we have... if (*pktsize < rssize) /* check size */ { -#ifdef GXS_TUNNEL_ITEM_DEBUG std::cerr << "GxsTunnel deserialisation: not enough size: pktsize=" << *pktsize << ", rssize=" << rssize << std::endl ; -#endif return NULL; /* not enough data */ } diff --git a/libretroshare/src/retroshare/rsplugin.h b/libretroshare/src/retroshare/rsplugin.h index e8cb91714..bb882c8dd 100644 --- a/libretroshare/src/retroshare/rsplugin.h +++ b/libretroshare/src/retroshare/rsplugin.h @@ -41,6 +41,7 @@ extern RsPluginHandler *rsPlugins ; class p3Service ; class RsServiceControl ; class RsTurtle ; +class RsGxsTunnelService ; class RsDht ; class RsDisc ; class RsMsgs ; @@ -116,6 +117,7 @@ public: RsUtil::inited_ptr mPgpAuxUtils; RsUtil::inited_ptr mGxsForums; RsUtil::inited_ptr mGxsChannels; + RsUtil::inited_ptr mGxsTunnels; }; class RsPlugin diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index f2f775649..684f08998 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -1475,6 +1475,7 @@ int RsServer::StartupRetroShare() pqih -> addService(ftserver,true); mGxsTunnels = new p3GxsTunnelService(mGxsIdService) ; + mGxsTunnels->connectToTurtleRouter(tr) ; rsGxsTunnel = mGxsTunnels; rsDisc = mDisc; @@ -1495,6 +1496,7 @@ int RsServer::StartupRetroShare() pqih -> addService(msgSrv,true); pqih -> addService(chatSrv,true); pqih -> addService(mStatusSrv,true); + pqih -> addService(mGxsTunnels,true); // set interfaces for plugins // @@ -1515,6 +1517,8 @@ int RsServer::StartupRetroShare() interfaces.mPgpAuxUtils = pgpAuxUtils; interfaces.mGxsForums = mGxsForums; interfaces.mGxsChannels = mGxsChannels; + interfaces.mGxsTunnels = mGxsTunnels; + mPluginsManager->setInterfaces(interfaces); // now add plugin objects inside the loop: From 81ab43beb9e7bd00a2224c52ba8c06ed54e005db Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 30 Nov 2015 00:02:44 -0500 Subject: [PATCH 14/26] fixed GUI update of avatars and status for distant chat. Updated backend for new model. Fixed a few bugs in serialisation --- libresapi/src/api/ChatHandler.cpp | 31 ++- libresapi/src/api/ChatHandler.h | 6 +- libretroshare/src/chat/distantchat.cc | 83 +++++++- libretroshare/src/chat/distantchat.h | 4 +- libretroshare/src/chat/p3chatservice.cc | 40 ++-- libretroshare/src/gxstunnel/p3gxstunnel.cc | 199 +++++++++++++----- libretroshare/src/gxstunnel/p3gxstunnel.h | 54 +++-- .../src/gxstunnel/rsgxstunnelitems.cc | 20 +- .../src/gxstunnel/rsgxstunnelitems.h | 2 +- libretroshare/src/pqi/p3cfgmgr.cc | 2 +- libretroshare/src/pqi/p3historymgr.cc | 25 +-- libretroshare/src/retroshare/rsgxstunnel.h | 25 ++- libretroshare/src/retroshare/rsids.h | 22 +- libretroshare/src/retroshare/rsmsgs.h | 17 +- libretroshare/src/rsserver/p3msgs.cc | 40 +++- libretroshare/src/rsserver/rsinit.cc | 2 +- libretroshare/src/services/p3gxschannels.cc | 2 +- libretroshare/src/upnp/upnphandler_linux.h | 4 +- retroshare-gui/src/gui/chat/ChatDialog.cpp | 16 +- .../src/gui/chat/ChatUserNotify.cpp | 2 +- retroshare-gui/src/gui/chat/ChatWidget.cpp | 121 ++++++----- .../src/gui/chat/PopupDistantChatDialog.cpp | 14 +- .../src/gui/chat/PopupDistantChatDialog.h | 2 +- .../src/gui/common/AvatarWidget.cpp | 64 +++--- retroshare-gui/src/gui/common/AvatarWidget.h | 1 - .../src/gui/im_history/ImHistoryBrowser.cpp | 4 +- .../src/gui/settings/RsharePeerSettings.cpp | 2 +- 27 files changed, 515 insertions(+), 289 deletions(-) diff --git a/libresapi/src/api/ChatHandler.cpp b/libresapi/src/api/ChatHandler.cpp index 81e41d8f5..49470d816 100644 --- a/libresapi/src/api/ChatHandler.cpp +++ b/libresapi/src/api/ChatHandler.cpp @@ -72,7 +72,7 @@ StreamBase& operator << (StreamBase& left, ChatHandler::Lobby& l) << makeKeyValueReference("subscribed", l.subscribed) << makeKeyValueReference("auto_subscribe", l.auto_subscribe) << makeKeyValueReference("is_private", l.is_private) - << makeKeyValueReference("gxs_id", l.gxs_id); + << makeKeyValueReference("distant_chat_id", l.distant_chat_id); return left; } @@ -81,7 +81,7 @@ StreamBase& operator << (StreamBase& left, ChatHandler::ChatInfo& info) left << makeKeyValueReference("remote_author_id", info.remote_author_id) << makeKeyValueReference("remote_author_name", info.remote_author_name) << makeKeyValueReference("is_broadcast", info.is_broadcast) - << makeKeyValueReference("is_gxs_id", info.is_gxs_id) + << makeKeyValueReference("is_distant_chat_id", info.is_distant_chat_id) << makeKeyValueReference("is_lobby", info.is_lobby) << makeKeyValueReference("is_peer", info.is_peer); return left; @@ -157,7 +157,7 @@ void ChatHandler::tick() l.subscribed = true; l.auto_subscribe = info.lobby_flags & RS_CHAT_LOBBY_FLAGS_AUTO_SUBSCRIBE; l.is_private = !(info.lobby_flags & RS_CHAT_LOBBY_FLAGS_PUBLIC); - l.gxs_id = info.gxs_id; + l.distant_chat_id.clear() ; lobbies.push_back(l); } } @@ -176,7 +176,7 @@ void ChatHandler::tick() l.subscribed = false; l.auto_subscribe = info.lobby_flags & RS_CHAT_LOBBY_FLAGS_AUTO_SUBSCRIBE; l.is_private = !(info.lobby_flags & RS_CHAT_LOBBY_FLAGS_PUBLIC); - l.gxs_id = RsGxsId(); + l.distant_chat_id.clear(); lobbies.push_back(l); } } @@ -199,11 +199,19 @@ void ChatHandler::tick() author_id = msg.broadcast_peer_id.toStdString(); author_name = mRsPeers->getPeerName(msg.broadcast_peer_id); } - else if(msg.chat_id.isGxsId()) + else if(msg.chat_id.isDistantChatId()) { - author_id = msg.chat_id.toGxsId().toStdString(); + DistantChatPeerInfo dcpinfo ; + + if(!rsMsgs->getDistantChatStatus(msg.chat_id.toDistantChatId(),dcpinfo)) + { + std::cerr << "(EE) cannot get info for distant chat peer " << msg.chat_id.toDistantChatId() << std::endl; + continue ; + } + + author_id = dcpinfo.to_id.toStdString(); RsIdentityDetails details; - if(!gxs_id_failed && mRsIdentity->getIdDetails(msg.chat_id.toGxsId(), details)) + if(!gxs_id_failed && mRsIdentity->getIdDetails(dcpinfo.to_id, details)) { author_name = details.mNickname; } @@ -252,7 +260,7 @@ void ChatHandler::tick() { ChatInfo info; info.is_broadcast = msg.chat_id.isBroadcast(); - info.is_gxs_id = msg.chat_id.isGxsId(); + info.is_distant_chat_id = msg.chat_id.isDistantChatId(); info.is_lobby = msg.chat_id.isLobbyId(); info.is_peer = msg.chat_id.isPeerId(); if(msg.chat_id.isLobbyId()) @@ -263,10 +271,13 @@ void ChatHandler::tick() info.remote_author_name = vit->name; } } - else if(msg.chat_id.isGxsId()) + else if(msg.chat_id.isDistantChatId()) { RsIdentityDetails details; - if(!gxs_id_failed && mRsIdentity->getIdDetails(msg.chat_id.toGxsId(), details)) + DistantChatPeerInfo dcpinfo ; + + if(!gxs_id_failed && rsMsgs->getDistantChatStatus(msg.chat_id.toDistantChatId(),dcpinfo) + && mRsIdentity->getIdDetails(dcpinfo.to_id, details)) { info.remote_author_id = msg.chat_id.toGxsId().toStdString(); info.remote_author_name = details.mNickname; diff --git a/libresapi/src/api/ChatHandler.h b/libresapi/src/api/ChatHandler.h index b849c2d98..59c5a4d77 100644 --- a/libresapi/src/api/ChatHandler.h +++ b/libresapi/src/api/ChatHandler.h @@ -65,7 +65,7 @@ public: bool auto_subscribe; bool is_private; - RsGxsId gxs_id;// for subscribed lobbies: the id we use to write messages + DistantChatPeerId distant_chat_id;// for subscribed lobbies: the id we use to write messages bool operator==(const Lobby& l) const { @@ -75,14 +75,14 @@ public: && subscribed == l.subscribed && auto_subscribe == l.auto_subscribe && is_private == l.is_private - && gxs_id == l.gxs_id; + && distant_chat_id == l.distant_chat_id; } }; class ChatInfo{ public: bool is_broadcast; - bool is_gxs_id; + bool is_distant_chat_id; bool is_lobby; bool is_peer; std::string remote_author_id; diff --git a/libretroshare/src/chat/distantchat.cc b/libretroshare/src/chat/distantchat.cc index 70d3cc140..eee035197 100644 --- a/libretroshare/src/chat/distantchat.cc +++ b/libretroshare/src/chat/distantchat.cc @@ -32,6 +32,7 @@ #include "util/rsaes.h" #include "util/rsmemory.h" +#include "util/rsprint.h" #include @@ -90,6 +91,8 @@ bool DistantChatService::handleOutgoingItem(RsChatItem *item) return false; } + std::cerr << " sending: " << RsUtil::BinToHex(mem,size) << std::endl; + mGxsTunnels->sendData( RsGxsTunnelId(item->PeerId()),DISTANT_CHAT_GXS_TUNNEL_SERVICE_ID,mem,size); return true; } @@ -108,18 +111,62 @@ void DistantChatService::handleRecvChatStatusItem(RsChatStatusItem *cs) void DistantChatService::notifyTunnelStatus(const RsGxsTunnelService::RsGxsTunnelId &tunnel_id, uint32_t tunnel_status) { std::cerr << "DistantChatService::notifyTunnelStatus(): got notification " << std::hex << tunnel_status << std::dec << " for tunnel " << tunnel_id << std::endl; -#warning do something here + + switch(tunnel_status) + { + default: + case RsGxsTunnelService::RS_GXS_TUNNEL_STATUS_UNKNOWN: std::cerr << "(EE) don't know how to handle RS_GXS_TUNNEL_STATUS_UNKNOWN !" << std::endl; + break ; + + case RsGxsTunnelService::RS_GXS_TUNNEL_STATUS_CAN_TALK: RsServer::notify()->notifyChatStatus(ChatId(DistantChatPeerId(tunnel_id)),"Tunnel is secured. You can talk!") ; + RsServer::notify()->notifyPeerStatusChanged(tunnel_id.toStdString(),RS_STATUS_ONLINE) ; + break ; + + case RsGxsTunnelService::RS_GXS_TUNNEL_STATUS_TUNNEL_DN: RsServer::notify()->notifyChatStatus(ChatId(DistantChatPeerId(tunnel_id)),"tunnel is down...") ; + RsServer::notify()->notifyPeerStatusChanged(tunnel_id.toStdString(),RS_STATUS_OFFLINE) ; + break ; + + case RsGxsTunnelService::RS_GXS_TUNNEL_STATUS_REMOTELY_CLOSED: RsServer::notify()->notifyChatStatus(ChatId(DistantChatPeerId(tunnel_id)),"tunnel is down...") ; + RsServer::notify()->notifyPeerStatusChanged(tunnel_id.toStdString(),RS_STATUS_OFFLINE) ; + break ; + } } void DistantChatService::receiveData(const RsGxsTunnelService::RsGxsTunnelId &tunnel_id, unsigned char *data, uint32_t data_size) { std::cerr << "DistantChatService::receiveData(): got data of size " << data_size << " for tunnel " << tunnel_id << std::endl; -#warning do something here + std::cerr << " received: " << RsUtil::BinToHex(data,data_size) << std::endl; + std::cerr << " deserialising..." << std::endl; + + RsItem *item = RsChatSerialiser().deserialise(data,&data_size) ; + + // always make the contact up to date. This is useful for server side, which doesn't know about the chat until it + // receives the first item. + { + RS_STACK_MUTEX(mDistantChatMtx) ; + + RsGxsTunnelService::GxsTunnelInfo tinfo; + if(!mGxsTunnels->getTunnelInfo(tunnel_id,tinfo)) + return ; + + DistantChatContact& contact(mDistantChatContacts[DistantChatPeerId(tunnel_id)]) ; + + contact.to_id = tinfo.destination_gxs_id ; + contact.from_id = tinfo.source_gxs_id ; + } + + if(item != NULL) + { + handleIncomingItem(item) ; + RsServer::notify()->notifyListChange(NOTIFY_LIST_PRIVATE_INCOMING_CHAT, NOTIFY_TYPE_ADD); + } + else + std::cerr << " (EE) item could not be deserialised!" << std::endl; } void DistantChatService::markDistantChatAsClosed(const DistantChatPeerId& dcpid) { - mGxsTunnels->closeExistingTunnel(RsGxsTunnelService::RsGxsTunnelId(dcpid)) ; + mGxsTunnels->closeExistingTunnel(RsGxsTunnelService::RsGxsTunnelId(dcpid),DISTANT_CHAT_GXS_TUNNEL_SERVICE_ID) ; RS_STACK_MUTEX(mDistantChatMtx) ; @@ -132,10 +179,10 @@ void DistantChatService::markDistantChatAsClosed(const DistantChatPeerId& dcpid) bool DistantChatService::initiateDistantChatConnexion(const RsGxsId& to_gxs_id, const RsGxsId& from_gxs_id, DistantChatPeerId& dcpid, uint32_t& error_code) { RsGxsTunnelId tunnel_id ; - - if(!mGxsTunnels->requestSecuredTunnel(to_gxs_id,from_gxs_id,tunnel_id,error_code)) + + if(!mGxsTunnels->requestSecuredTunnel(to_gxs_id,from_gxs_id,tunnel_id,DISTANT_CHAT_GXS_TUNNEL_SERVICE_ID,error_code)) return false ; - + dcpid = DistantChatPeerId(tunnel_id) ; DistantChatContact& dc_contact(mDistantChatContacts[dcpid]) ; @@ -145,6 +192,14 @@ bool DistantChatService::initiateDistantChatConnexion(const RsGxsId& to_gxs_id, error_code = RS_DISTANT_CHAT_ERROR_NO_ERROR ; + // Make a self message to raise the chat window + + RsChatMsgItem *item = new RsChatMsgItem; + item->message = "[Starting distant chat. Please wait for secure tunnel to be established]" ; + item->chatFlags = RS_CHAT_FLAG_PRIVATE ; + item->PeerId(RsPeerId(tunnel_id)) ; + handleRecvChatMsgItem(item) ; + return true ; } @@ -160,14 +215,26 @@ bool DistantChatService::getDistantChatStatus(const DistantChatPeerId& tunnel_id cinfo.to_id = tinfo.destination_gxs_id; cinfo.own_id = tinfo.source_gxs_id; cinfo.peer_id = tunnel_id; - cinfo.status = tinfo.tunnel_status; // see the values in rsmsgs.h + + switch(tinfo.tunnel_status) + { + case RsGxsTunnelService::RS_GXS_TUNNEL_STATUS_CAN_TALK : cinfo.status = RS_DISTANT_CHAT_STATUS_CAN_TALK; + break ; + case RsGxsTunnelService::RS_GXS_TUNNEL_STATUS_TUNNEL_DN: cinfo.status = RS_DISTANT_CHAT_STATUS_TUNNEL_DN ; + break ; + case RsGxsTunnelService::RS_GXS_TUNNEL_STATUS_REMOTELY_CLOSED: cinfo.status = RS_DISTANT_CHAT_STATUS_REMOTELY_CLOSED ; + break ; + default: + case RsGxsTunnelService::RS_GXS_TUNNEL_STATUS_UNKNOWN: cinfo.status = RS_DISTANT_CHAT_STATUS_UNKNOWN; + break ; + } return true ; } bool DistantChatService::closeDistantChatConnexion(const DistantChatPeerId &tunnel_id) { - mGxsTunnels->closeExistingTunnel(RsGxsTunnelId(tunnel_id)) ; + mGxsTunnels->closeExistingTunnel(RsGxsTunnelId(tunnel_id), DISTANT_CHAT_GXS_TUNNEL_SERVICE_ID) ; // also remove contact. Or do we wait for the notification? diff --git a/libretroshare/src/chat/distantchat.h b/libretroshare/src/chat/distantchat.h index b13a0aa7e..20435dc63 100644 --- a/libretroshare/src/chat/distantchat.h +++ b/libretroshare/src/chat/distantchat.h @@ -39,7 +39,7 @@ public: // So, public interface only uses DistandChatPeerId, but internally, this is converted into a RsGxsTunnelService::RsGxsTunnelId - DistantChatService(RsGixs *pids) : mDistantChatMtx("distant chat") + DistantChatService() : mDistantChatMtx("distant chat") { mGxsTunnels = NULL ; } @@ -56,7 +56,7 @@ public: virtual bool getDistantChatStatus(const DistantChatPeerId &tunnel_id, DistantChatPeerInfo& cinfo) ; - // derived in p3ChatService + // derived in p3ChatService, so as to pass down some info virtual void handleIncomingItem(RsItem *) = 0; virtual bool handleRecvChatMsgItem(RsChatMsgItem *ci)=0 ; diff --git a/libretroshare/src/chat/p3chatservice.cc b/libretroshare/src/chat/p3chatservice.cc index f7a8050b5..e6b0215c1 100644 --- a/libretroshare/src/chat/p3chatservice.cc +++ b/libretroshare/src/chat/p3chatservice.cc @@ -54,7 +54,7 @@ static const uint32_t MAX_AVATAR_JPEG_SIZE = 32767; // Maximum size // Images are 96x96, which makes approx. 27000 bytes uncompressed. p3ChatService::p3ChatService(p3ServiceControl *sc,p3IdService *pids, p3LinkMgr *lm, p3HistoryMgr *historyMgr) - :DistantChatService(pids),DistributedChatService(getServiceInfo().mServiceType,sc,historyMgr,pids), mChatMtx("p3ChatService"),mServiceCtrl(sc), mLinkMgr(lm) , mHistoryMgr(historyMgr) + : DistributedChatService(getServiceInfo().mServiceType,sc,historyMgr,pids), mChatMtx("p3ChatService"),mServiceCtrl(sc), mLinkMgr(lm) , mHistoryMgr(historyMgr) { _serializer = new RsChatSerialiser() ; @@ -217,24 +217,25 @@ void p3ChatService::sendStatusString(const ChatId& id , const std::string& statu sendLobbyStatusString(id.toLobbyId(),status_string) ; else if(id.isBroadcast()) sendGroupChatStatusString(status_string); - else if(id.isPeerId() || id.isGxsId()) - { - RsChatStatusItem *cs = new RsChatStatusItem ; + else if(id.isPeerId() || id.isDistantChatId()) + { + RsChatStatusItem *cs = new RsChatStatusItem ; - cs->status_string = status_string ; - cs->flags = RS_CHAT_FLAG_PRIVATE ; - RsPeerId vpid; - if(id.isGxsId()) - vpid = RsPeerId(id.toGxsId()); - else - vpid = id.toPeerId(); - cs->PeerId(vpid); + cs->status_string = status_string ; + cs->flags = RS_CHAT_FLAG_PRIVATE ; + RsPeerId vpid; + if(id.isDistantChatId()) + vpid = RsPeerId(id.toDistantChatId()); + else + vpid = id.toPeerId(); + + cs->PeerId(vpid); #ifdef CHAT_DEBUG - std::cerr << "sending chat status packet:" << std::endl ; - cs->print(std::cerr) ; + std::cerr << "sending chat status packet:" << std::endl ; + cs->print(std::cerr) ; #endif - sendChatItem(cs); + sendChatItem(cs); } else { @@ -286,7 +287,6 @@ bool p3ChatService::isOnline(const RsPeerId& pid) { // check if the id is a tunnel id or a peer id. - uint32_t status ; DistantChatPeerInfo dcpinfo; if(getDistantChatStatus(DistantChatPeerId(pid),dcpinfo)) @@ -304,7 +304,7 @@ bool p3ChatService::sendChat(ChatId destination, std::string msg) sendPublicChat(msg); return true; } - else if(destination.isPeerId()==false && destination.isGxsId()==false) + else if(destination.isPeerId()==false && destination.isDistantChatId()==false) { std::cerr << "p3ChatService::sendChat() Error: chat id type not handled. Is it empty?" << std::endl; return false; @@ -316,8 +316,8 @@ bool p3ChatService::sendChat(ChatId destination, std::string msg) #endif RsPeerId vpid; - if(destination.isGxsId()) - vpid = RsPeerId(destination.toGxsId()); // convert to virtual peer id + if(destination.isDistantChatId()) + vpid = RsPeerId(destination.toDistantChatId()); // convert to virtual peer id else vpid = destination.toPeerId(); @@ -769,7 +769,6 @@ void p3ChatService::handleRecvChatStatusItem(RsChatStatusItem *cs) std::cerr << "Received status string \"" << cs->status_string << "\"" << std::endl ; #endif - uint32_t status; DistantChatPeerInfo dcpinfo; if(cs->flags & RS_CHAT_FLAG_REQUEST_CUSTOM_STATE) // no state here just a request. @@ -820,7 +819,6 @@ void p3ChatService::initChatMessage(RsChatMsgItem *c, ChatMessage &m) return; } - uint32_t status; DistantChatPeerInfo dcpinfo; if(DistantChatService::getDistantChatStatus(DistantChatPeerId(c->PeerId()), dcpinfo)) m.chat_id = ChatId(DistantChatPeerId(c->PeerId())); diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.cc b/libretroshare/src/gxstunnel/p3gxstunnel.cc index 043869800..2460bb9aa 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.cc +++ b/libretroshare/src/gxstunnel/p3gxstunnel.cc @@ -113,6 +113,8 @@ int p3GxsTunnelService::tick() } flush() ; + + return 0 ; } RsServiceInfo p3GxsTunnelService::getServiceInfo() @@ -199,8 +201,8 @@ void p3GxsTunnelService::flush() { RsGxsTunnelStatusItem *cs = new RsGxsTunnelStatusItem ; - cs->flags = RS_GXS_TUNNEL_FLAG_KEEP_ALIVE; - cs->PeerId(it->second.virtual_peer_id) ; + cs->status = RS_GXS_TUNNEL_FLAG_KEEP_ALIVE; + cs->PeerId(RsPeerId(it->first)) ; // we send off-mutex to avoid deadlock. @@ -274,7 +276,7 @@ void p3GxsTunnelService::handleRecvTunnelDataItem(const RsGxsTunnelId& tunnel_id RsGxsTunnelDataAckItem *ackitem = new RsGxsTunnelDataAckItem ; ackitem->unique_item_counter = item->unique_item_counter ; - ackitem->PeerId(item->PeerId()); + ackitem->PeerId(RsPeerId(tunnel_id)) ; { RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ @@ -299,6 +301,11 @@ void p3GxsTunnelService::handleRecvTunnelDataItem(const RsGxsTunnelId& tunnel_id return ; } service = it->second ; + + std::map::iterator it2 = _gxs_tunnel_contacts.find(tunnel_id) ; + + if(it2 != _gxs_tunnel_contacts.end()) + it2->second.client_services.insert(item->service_id) ; } service->receiveData(tunnel_id,item->data,item->data_size) ; @@ -309,13 +316,84 @@ void p3GxsTunnelService::handleRecvTunnelDataItem(const RsGxsTunnelId& tunnel_id void p3GxsTunnelService::handleRecvStatusItem(const RsGxsTunnelId& tunnel_id, RsGxsTunnelStatusItem *cs) { - if(cs->flags & RS_GXS_TUNNEL_FLAG_CLOSING_DISTANT_CONNECTION) - markGxsTunnelAsClosed(tunnel_id); + std::vector notifications ; + std::set clients ; - // nothing more to do, because the decryption routing will update the last_contact time when decrypting. + std::cerr << "p3GxsTunnelService::handleRecvStatusItem(): tunnel_id=" << tunnel_id << " status=" << cs->status << std::endl; - if(cs->flags & RS_GXS_TUNNEL_FLAG_KEEP_ALIVE) - std::cerr << "GxsTunnelService::handleRecvGxsTunnelStatusItem(): received keep alive packet for inactive tunnel! peerId=" << cs->PeerId() << " tunnel=" << tunnel_id << std::endl; + switch(cs->status) + { + case RS_GXS_TUNNEL_FLAG_CLOSING_DISTANT_CONNECTION: + { + RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + + std::map::iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; + + if(it == _gxs_tunnel_contacts.end()) + { + std::cerr << "(EE) Cannot mark tunnel connection as closed. No connection openned for tunnel id " << tunnel_id << ". Unexpected situation." << std::endl; + return ; + } + + if(it->second.direction == RsTurtleGenericDataItem::DIRECTION_CLIENT) + { +#ifdef DEBUG_GXS_TUNNEL + std::cerr << " This is server side. Marking distant chat as remotely closed for tunnel id " << tunnel_id << std::endl; +#endif + it->second.status = RS_GXS_TUNNEL_STATUS_REMOTELY_CLOSED ; + notifications.push_back(RS_GXS_TUNNEL_STATUS_REMOTELY_CLOSED) ; + } + } // nothing more to do, because the decryption routing will update the last_contact time when decrypting. + break ; + + case RS_GXS_TUNNEL_FLAG_KEEP_ALIVE: + std::cerr << "GxsTunnelService::handleRecvGxsTunnelStatusItem(): received keep alive packet for inactive tunnel! peerId=" << cs->PeerId() << " tunnel=" << tunnel_id << std::endl; + break ; + + case RS_GXS_TUNNEL_FLAG_ACK_DISTANT_CONNECTION: + { + std::cerr << "Received ACK item from the distant peer!" << std::endl; + + // in this case we notify the clients using this tunnel. + + notifications.push_back(RS_GXS_TUNNEL_STATUS_CAN_TALK) ; + } + break ; + + default: + std::cerr << "(EE) unhandled tunnel status " << std::hex << cs->status << std::dec << std::endl; + break ; + } + + // notify all clients + + std::cerr << " notifying clients. Prending notifications: " << notifications.size() << std::endl; + + if(notifications.size() > 0) + { + RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + + std::map::iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; + + std::cerr << " " << it->second.client_services.size() << " client services for tunnel id " << tunnel_id << std::endl; + + for(std::set::const_iterator it2(it->second.client_services.begin());it2!=it->second.client_services.end();++it2) + { + std::map::const_iterator it3=mRegisteredServices.find(*it2) ; + + if(it3 != mRegisteredServices.end()) + clients.insert(it3->second) ; + } + } + + std::cerr << " notifying " << clients.size() << " clients." << std::endl; + + for(std::set::const_iterator it(clients.begin());it!=clients.end();++it) + for(uint32_t i=0;inotifyTunnelStatus(tunnel_id,notifications[i]) ; + std::cerr << " notifying client " << (void*)(*it) << " of status " << notifications[i] << std::endl; + } } bool p3GxsTunnelService::handleTunnelRequest(const RsFileHash& hash,const RsPeerId& /*peer_id*/) @@ -435,6 +513,8 @@ void p3GxsTunnelService::locked_restartDHSession(const RsPeerId& virtual_peer_id void p3GxsTunnelService::removeVirtualPeer(const TurtleFileHash& hash,const TurtleVirtualPeerId& virtual_peer_id) { bool tunnel_dn = false ; + std::set client_services ; + RsGxsTunnelId tunnel_id ; #ifdef DEBUG_GXS_TUNNEL std::cerr << "GxsTunnelService: Removing virtual peer " << virtual_peer_id << " for hash " << hash << std::endl; @@ -454,7 +534,7 @@ void p3GxsTunnelService::removeVirtualPeer(const TurtleFileHash& hash,const Turt return ; } - RsGxsTunnelId tunnel_id = it->second.tunnel_id ; + tunnel_id = it->second.tunnel_id ; if(it->second.dh != NULL) DH_free(it->second.dh) ; @@ -474,13 +554,22 @@ void p3GxsTunnelService::removeVirtualPeer(const TurtleFileHash& hash,const Turt it2->second.virtual_peer_id.clear() ; tunnel_dn = true ; } + + for(std::set::const_iterator it(it2->second.client_services.begin());it!=it2->second.client_services.end();++it) + { + std::map::const_iterator it2 = mRegisteredServices.find(*it) ; + + if(it2 != mRegisteredServices.end()) + client_services.insert(it2->second) ; + } } if(tunnel_dn) { -#warning we should notify the client here - //RsServer::notify()->notifyChatStatus(ChatId(RsGxsId(virtual_peer_id)),"tunnel is down...") ; - //RsServer::notify()->notifyPeerStatusChanged(virtual_peer_id.toStdString(),RS_STATUS_OFFLINE) ; + // notify all client services that this tunnel is down + + for(std::set::const_iterator it(client_services.begin());it!=client_services.end();++it) + (*it)->notifyTunnelStatus(tunnel_id,RS_GXS_TUNNEL_STATUS_TUNNEL_DN) ; } } @@ -824,8 +913,8 @@ void p3GxsTunnelService::handleRecvDHPublicKey(RsGxsTunnelDHPublicKeyItem *item) RsGxsTunnelStatusItem *cs = new RsGxsTunnelStatusItem ; - cs->flags = RS_GXS_TUNNEL_FLAG_ACK_DISTANT_CONNECTION; - cs->PeerId(vpid) ; + cs->status = RS_GXS_TUNNEL_FLAG_ACK_DISTANT_CONNECTION; + cs->PeerId(RsPeerId(tunnel_id)) ; pendingGxsTunnelItems.push_back(cs) ; } @@ -958,7 +1047,9 @@ bool p3GxsTunnelService::locked_initDHSessionKey(DH *& dh) return true ; } -// Encrypts and sends the item. +// Sends the item in clear. This is only used for DH key exchange. +// in this case only, the item's PeerId is equal to the virtual peer Id for the tunnel, +// since we ight not now the tunnel id yet. bool p3GxsTunnelService::locked_sendClearTunnelData(RsGxsTunnelDHPublicKeyItem *item) { @@ -1013,27 +1104,21 @@ bool p3GxsTunnelService::locked_sendEncryptedTunnelData(RsGxsTunnelItem *item) uint64_t IV = 0; #ifdef DEBUG_GXS_TUNNEL - std::cerr << "Sending encrypted data to tunnel wuth vpid " << item->PeerId() << std::endl; + std::cerr << "Sending encrypted data to tunnel with vpid " << item->PeerId() << std::endl; #endif - TurtleVirtualPeerId vpid = item->PeerId() ; + + RsGxsTunnelId tunnel_id ( item->PeerId() ); - std::map::const_iterator it2 = _gxs_tunnel_virtual_peer_ids.find(vpid) ; - if(it2 == _gxs_tunnel_virtual_peer_ids.end()) - { - std::cerr << "(EE) no virtual peer " << vpid << ". Something's wrong!" << std::endl; - return false; - } - - std::map::iterator it = _gxs_tunnel_contacts.find(it2->second.tunnel_id) ; + std::map::iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; if(it == _gxs_tunnel_contacts.end()) { - std::cerr << "(EE) Cannot find contact key info for virtual peer id " << vpid << ". Cannot send message!" << std::endl; + std::cerr << "(EE) Cannot find contact key info for tunnel id " << tunnel_id << ". Cannot send message!" << std::endl; return false; } if(it->second.status != RS_GXS_TUNNEL_STATUS_CAN_TALK) { - std::cerr << "(EE) Cannot talk to vpid " << vpid << ". Tunnel status is: " << it->second.status << std::endl; + std::cerr << "(EE) Cannot talk to tunnel id " << tunnel_id << ". Tunnel status is: " << it->second.status << std::endl; return false; } @@ -1075,7 +1160,7 @@ bool p3GxsTunnelService::locked_sendEncryptedTunnelData(RsGxsTunnelItem *item) #ifdef DEBUG_GXS_TUNNEL std::cerr << " Using IV: " << std::hex << IV << std::dec << std::endl; std::cerr << " Using Key: " << RsUtil::BinToHex((char*)aes_key,GXS_TUNNEL_AES_KEY_SIZE) ; std::cerr << std::endl; - std::cerr << " hmac: " << RsUtil::BinToHex((char*)gitem->data_bytes,GXS_TUNNEL_ENCRYPTION_HMAC_SIZE) ; + std::cerr << " hmac: " << RsUtil::BinToHex((char*)gitem->data_bytes,GXS_TUNNEL_ENCRYPTION_HMAC_SIZE) << std::endl; #endif #ifdef DEBUG_GXS_TUNNEL std::cerr << "GxsTunnelService::sendEncryptedTunnelData(): Sending encrypted data to virtual peer: " << virtual_peer_id << std::endl; @@ -1089,7 +1174,7 @@ bool p3GxsTunnelService::locked_sendEncryptedTunnelData(RsGxsTunnelItem *item) return true ; } -bool p3GxsTunnelService::requestSecuredTunnel(const RsGxsId& to_gxs_id, const RsGxsId& from_gxs_id, RsGxsTunnelId &tunnel_id, uint32_t& error_code) +bool p3GxsTunnelService::requestSecuredTunnel(const RsGxsId& to_gxs_id, const RsGxsId& from_gxs_id, RsGxsTunnelId &tunnel_id, uint32_t service_id, uint32_t& error_code) { // should be a parameter. @@ -1112,7 +1197,7 @@ bool p3GxsTunnelService::requestSecuredTunnel(const RsGxsId& to_gxs_id, const Rs } RsGxsId own_gxs_id = from_gxs_id ; - startClientGxsTunnelConnection(to_gxs_id,own_gxs_id,tunnel_id) ; + startClientGxsTunnelConnection(to_gxs_id,own_gxs_id,service_id,tunnel_id) ; error_code = RS_GXS_TUNNEL_ERROR_NO_ERROR ; @@ -1155,6 +1240,7 @@ bool p3GxsTunnelService::sendData(const RsGxsTunnelId &tunnel_id, uint32_t servi item->service_id = service_id; item->data_size = size; // encrypted data size item->data = (uint8_t*)malloc(size); // encrypted data + item->PeerId(RsPeerId(tunnel_id)) ; memcpy(item->data,data,size) ; GxsTunnelData& tdata( pendingGxsTunnelDataItems[item->unique_item_counter] ) ; @@ -1168,7 +1254,7 @@ bool p3GxsTunnelService::sendData(const RsGxsTunnelId &tunnel_id, uint32_t servi } -void p3GxsTunnelService::startClientGxsTunnelConnection(const RsGxsId& to_gxs_id,const RsGxsId& from_gxs_id,RsGxsTunnelId& tunnel_id) +void p3GxsTunnelService::startClientGxsTunnelConnection(const RsGxsId& to_gxs_id,const RsGxsId& from_gxs_id,uint32_t service_id,RsGxsTunnelId& tunnel_id) { // compute a random hash for that pair, and init the DH session for it so that we can recognise it when we get the virtual peer for it. @@ -1198,6 +1284,7 @@ void p3GxsTunnelService::startClientGxsTunnelConnection(const RsGxsId& to_gxs_id info.hash = hash ; info.direction = RsTurtleGenericTunnelItem::DIRECTION_SERVER ; info.virtual_peer_id.clear(); + info.client_services.insert(service_id) ; memset(info.aes_key,0,GXS_TUNNEL_AES_KEY_SIZE) ; @@ -1222,8 +1309,6 @@ TurtleFileHash p3GxsTunnelService::randomHashFromDestinationGxsId(const RsGxsId& // This is in prevision for the "secured GXS tunnel" service, which will need a service ID to register, // just like GRouter does. - static const uint32_t client = RS_SERVICE_TYPE_GXS_TUNNEL ; - assert( destination.SIZE_IN_BYTES == 16) ; assert(Sha1CheckSum::SIZE_IN_BYTES == 20) ; @@ -1289,7 +1374,7 @@ bool p3GxsTunnelService::getTunnelStatus(const RsGxsTunnelId& tunnel_id,uint32_t return false ; } -bool p3GxsTunnelService::closeExistingTunnel(const RsGxsTunnelId& tunnel_id) +bool p3GxsTunnelService::closeExistingTunnel(const RsGxsTunnelId& tunnel_id, uint32_t service_id) { // two cases: // - client needs to stop asking for tunnels => remove the hash from the list of tunnelled files @@ -1298,9 +1383,10 @@ bool p3GxsTunnelService::closeExistingTunnel(const RsGxsTunnelId& tunnel_id) TurtleFileHash hash ; TurtleVirtualPeerId vpid ; + bool close_tunnel = false ; { RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - std::map::const_iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; + std::map::iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; if(it == _gxs_tunnel_contacts.end()) { @@ -1319,16 +1405,34 @@ bool p3GxsTunnelService::closeExistingTunnel(const RsGxsTunnelId& tunnel_id) if(it2 != _gxs_tunnel_virtual_peer_ids.end()) hash = it2->second.hash ; + + // check how many clients are used. If empty, close the tunnel + + std::set::iterator it3 = it->second.client_services.find(service_id) ; + + if(it3 == it->second.client_services.end()) + { + std::cerr << "(EE) service id not currently using that tunnel. This is an error." << std::endl; + return false; + } + + it->second.client_services.erase(it3) ; + + if(it->second.client_services.empty()) + close_tunnel = true ; } + if(!close_tunnel) + return true ; + // send a status item saying that we're closing the connection #ifdef DEBUG_GXS_TUNNEL - std::cerr << " Sending a ACK to close the tunnel since we're managing it. tunnel id=." << tunnel_id << std::endl; + std::cerr << " Sending a ACK to close the tunnel since we're managing it and it's not used by any service. tunnel id=." << tunnel_id << std::endl; #endif RsGxsTunnelStatusItem *cs = new RsGxsTunnelStatusItem ; - cs->flags = RS_GXS_TUNNEL_FLAG_CLOSING_DISTANT_CONNECTION; + cs->status = RS_GXS_TUNNEL_FLAG_CLOSING_DISTANT_CONNECTION; cs->PeerId(vpid) ; locked_sendEncryptedTunnelData(cs) ; // that needs to be done off-mutex and before we close the tunnel also ignoring failure. @@ -1354,27 +1458,6 @@ bool p3GxsTunnelService::closeExistingTunnel(const RsGxsTunnelId& tunnel_id) return true ; } -void p3GxsTunnelService::markGxsTunnelAsClosed(const RsGxsTunnelId& tunnel_id) -{ - RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - - std::map::iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; - - if(it == _gxs_tunnel_contacts.end()) - { - std::cerr << "(EE) Cannot mark distant chat connection as closed. No connection openned for tunnel id " << tunnel_id << ". Unexpected situation." << std::endl; - return ; - } - - if(it->second.direction == RsTurtleGenericDataItem::DIRECTION_CLIENT) - { -#ifdef DEBUG_GXS_TUNNEL - std::cerr << " This is server side. Marking distant chat as remotely closed for tunnel id " << tunnel_id << std::endl; -#endif - it->second.status = RS_GXS_TUNNEL_STATUS_REMOTELY_CLOSED ; - } -} - void p3GxsTunnelService::debug_dump() { RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.h b/libretroshare/src/gxstunnel/p3gxstunnel.h index 9138f9f86..3163de06f 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.h +++ b/libretroshare/src/gxstunnel/p3gxstunnel.h @@ -45,7 +45,7 @@ // // Interaction with services: // -// Services request tunnels from a given GXS id and to a given GXS id. When ready, they get a handle (virtual peer id) +// Services request tunnels from a given GXS id and to a given GXS id. When ready, they get a handle (type = RsGxsTunnelId) // // Services send data in the tunnel using the virtual peer id // @@ -56,6 +56,18 @@ // // Tunnel establishment // * we need two layers: the turtle layer, and the GXS id layer. +// - for each pair of GXS ids talking, a single turtle tunnel is used +// - that tunnel can be shared by multiple services using it. +// - services are responsoble for asking tunnels and also droppping them when unused. +// - at the turtle layer, the tunnel will be closed only when no service uses it. +// * IDs +// TurtleVirtualPeerId: +// - Used by tunnel service for each turtle tunnel +// - one virtual peer ID per GXS tunnel +// +// GxsTunnelId: +// - one GxsTunnelId per couple of GXS ids. But we also need to allow multiple services to use the tunnel. +// // * at the turtle layer: // - accept virtual peers from turtle tunnel service. The hash for that VP only depends on the server GXS id at server side, which is our // own ID at server side, and destination ID at client side. What happens if two different clients request to talk to the same GXS id? (same hash) @@ -80,22 +92,22 @@ // // -// RequestTunnel(source_own_id,destination_id) -// | -// +---------------------------> p3Turtle::monitorTunnels( hash(destination_id) ) -// | -// [Turtle async work] -------------------+ -// | | -// handleTunnelRequest() <-----------------------------------------------+ | -// | | -// +---------------- keep record in _gxs_tunnel_virtual_peer_id, initiate DH exchange | -// | -// handleDHPublicKey() <-----------------------------------------------------------------------------+ -// | -// +---------------- update _gxs_tunnel_contacts[ tunnel_hash = hash(own_id, destination_id) ] -// | -// +---------------- notify client service that Peer(destination_id, tunnel_hash) is ready to talk to -// +// RequestTunnel(source_own_id,destination_id) - +// | | +// +---------------------------> p3Turtle::monitorTunnels( hash(destination_id) ) | +// | | +// [Turtle async work] -------------------+ | Turtle layer: one virtual peer id +// | | | +// handleTunnelRequest() <-----------------------------------------------+ | | +// | | | +// +---------------- keep record in _gxs_tunnel_virtual_peer_id, initiate DH exchange | - +// | | +// handleDHPublicKey() <-----------------------------------------------------------------------------+ | +// | | +// +---------------- update _gxs_tunnel_contacts[ tunnel_hash = hash(own_id, destination_id) ] | GxsTunnelId level +// | | +// +---------------- notify client service that Peer(destination_id, tunnel_hash) is ready to talk to | +// - // Notes // * one other option would be to make the turtle hash depend on both GXS ids in a way that it is possible to find which are the two ids on the server side. // but that would prevent the use of unknown IDs, which we would like to offer as well. @@ -123,9 +135,9 @@ public: // 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. // - virtual bool requestSecuredTunnel(const RsGxsId& to_id,const RsGxsId& from_id,RsGxsTunnelId& tunnel_id,uint32_t& error_code) ; + virtual bool requestSecuredTunnel(const RsGxsId& to_id,const RsGxsId& from_id,RsGxsTunnelId& tunnel_id,uint32_t service_id,uint32_t& error_code) ; - virtual bool closeExistingTunnel(const RsGxsTunnelId &tunnel_id) ; + virtual bool closeExistingTunnel(const RsGxsTunnelId &tunnel_id,uint32_t service_id) ; virtual bool getTunnelStatus(const RsGxsTunnelId& tunnel_id,uint32_t &status); virtual bool getTunnelInfo(const RsGxsTunnelId& tunnel_id,GxsTunnelInfo& info); virtual bool sendData(const RsGxsTunnelId& tunnel_id,uint32_t service_id,const uint8_t *data,uint32_t size) ; @@ -160,6 +172,7 @@ private: RsGxsId own_gxs_id ; // gxs id we're using to talk. RsTurtleGenericTunnelItem::Direction direction ; // specifiec wether we are client(managing the tunnel) or server. TurtleFileHash hash ; // hash that is last used. This is necessary for handling tunnel establishment + std::set client_services ;// services that used this tunnel }; class GxsTunnelDHInfo @@ -203,8 +216,7 @@ private: // session handling handles - void markGxsTunnelAsClosed(const RsGxsTunnelId &tunnel_id) ; - void startClientGxsTunnelConnection(const RsGxsId &to_gxs_id, const RsGxsId& from_gxs_id, RsGxsTunnelId &tunnel_id) ; + void startClientGxsTunnelConnection(const RsGxsId &to_gxs_id, const RsGxsId& from_gxs_id, uint32_t service_id, RsGxsTunnelId &tunnel_id) ; void locked_restartDHSession(const RsPeerId &virtual_peer_id, const RsGxsId &own_gxs_id) ; // utility functions diff --git a/libretroshare/src/gxstunnel/rsgxstunnelitems.cc b/libretroshare/src/gxstunnel/rsgxstunnelitems.cc index 055fb4ba0..ebc818228 100644 --- a/libretroshare/src/gxstunnel/rsgxstunnelitems.cc +++ b/libretroshare/src/gxstunnel/rsgxstunnelitems.cc @@ -79,7 +79,7 @@ std::ostream& RsGxsTunnelStatusItem::print(std::ostream &out, uint16_t indent) uint16_t int_Indent = indent + 2; printIndent(out, int_Indent); - out << " flags : " << std::hex << flags << std::dec << std::endl ; + out << " flags : " << std::hex << status << std::dec << std::endl ; printRsItemEnd(out, "RsGxsTunnelStatusItem", indent); return out; @@ -235,7 +235,7 @@ bool RsGxsTunnelStatusItem::serialise(void *data, uint32_t& pktsize) offset += 8; /* add mandatory parts first */ - ok &= setRawUInt32(data, tlvsize, &offset, flags); + ok &= setRawUInt32(data, tlvsize, &offset, status); if (offset != tlvsize) { @@ -249,7 +249,7 @@ bool RsGxsTunnelStatusItem::serialise(void *data, uint32_t& pktsize) return ok; } -bool RsGxsTunnelDataItem::serialise(void *data, uint32_t& pktsize) +bool RsGxsTunnelDataItem::serialise(void *dt, uint32_t& pktsize) { uint32_t tlvsize = serial_size() ; uint32_t offset = 0; @@ -261,7 +261,7 @@ bool RsGxsTunnelDataItem::serialise(void *data, uint32_t& pktsize) bool ok = true; - ok &= setRsItemHeader(data, tlvsize, PacketId(), tlvsize); + ok &= setRsItemHeader(dt, tlvsize, PacketId(), tlvsize); #ifdef GXS_TUNNEL_ITEM_DEBUG std::cerr << "RsGxsTunnelSerialiser serialising chat status item." << std::endl; @@ -273,14 +273,14 @@ bool RsGxsTunnelDataItem::serialise(void *data, uint32_t& pktsize) offset += 8; /* add mandatory parts first */ - ok &= setRawUInt64(data, tlvsize, &offset, unique_item_counter); - ok &= setRawUInt32(data, tlvsize, &offset, flags); - ok &= setRawUInt32(data, tlvsize, &offset, service_id); - ok &= setRawUInt32(data, tlvsize, &offset, data_size); + ok &= setRawUInt64(dt, tlvsize, &offset, unique_item_counter); + ok &= setRawUInt32(dt, tlvsize, &offset, flags); + ok &= setRawUInt32(dt, tlvsize, &offset, service_id); + ok &= setRawUInt32(dt, tlvsize, &offset, data_size); if(offset + data_size <= tlvsize) { - memcpy(&((uint8_t*)data)[offset],data,data_size) ; + memcpy(&((uint8_t*)dt)[offset],data,data_size) ; offset += data_size ; } else @@ -451,7 +451,7 @@ RsGxsTunnelStatusItem *RsGxsTunnelSerialiser::deserialise_RsGxsTunnelStatusItem( /* get mandatory parts first */ - ok &= getRawUInt32(dat, rssize, &offset, &item->flags); + ok &= getRawUInt32(dat, rssize, &offset, &item->status); if (offset != rssize) { diff --git a/libretroshare/src/gxstunnel/rsgxstunnelitems.h b/libretroshare/src/gxstunnel/rsgxstunnelitems.h index a5bd1d7b4..d1abf8c20 100644 --- a/libretroshare/src/gxstunnel/rsgxstunnelitems.h +++ b/libretroshare/src/gxstunnel/rsgxstunnelitems.h @@ -105,7 +105,7 @@ class RsGxsTunnelStatusItem: public RsGxsTunnelItem 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 - uint32_t flags ; + uint32_t status ; }; // Used to confirm reception of an encrypted item. diff --git a/libretroshare/src/pqi/p3cfgmgr.cc b/libretroshare/src/pqi/p3cfgmgr.cc index 03a3f720e..6f11af038 100644 --- a/libretroshare/src/pqi/p3cfgmgr.cc +++ b/libretroshare/src/pqi/p3cfgmgr.cc @@ -208,7 +208,7 @@ p3Config::p3Config() } -bool p3Config::loadConfiguration(RsFileHash &loadHash) +bool p3Config::loadConfiguration(RsFileHash& /* loadHash */) { return loadConfig(); } diff --git a/libretroshare/src/pqi/p3historymgr.cc b/libretroshare/src/pqi/p3historymgr.cc index 8b6887f23..b4f5c3068 100644 --- a/libretroshare/src/pqi/p3historymgr.cc +++ b/libretroshare/src/pqi/p3historymgr.cc @@ -99,17 +99,14 @@ void p3HistoryMgr::addMessage(const ChatMessage& cm) enabled = true; } - if (cm.chat_id.isGxsId() && mPrivateEnable == true) { - if (cm.incoming) { - peerName = cm.chat_id.toGxsId().toStdString(); - } else { - uint32_t status; - DistantChatPeerInfo dcpinfo; - if (rsMsgs->getDistantChatStatus(cm.chat_id.toPeerId(), dcpinfo)) - peerName = cm.chat_id.toPeerId().toStdString(); - } - enabled = true; - } + if(cm.chat_id.isDistantChatId()) + { + uint32_t status; + DistantChatPeerInfo dcpinfo; + if (rsMsgs->getDistantChatStatus(cm.chat_id.toDistantChatId(), dcpinfo)) + peerName = cm.chat_id.toPeerId().toStdString(); + enabled = true; + } if(enabled == false) return; @@ -397,8 +394,8 @@ bool p3HistoryMgr::chatIdToVirtualPeerId(ChatId chat_id, RsPeerId &peer_id) return true; } - if (chat_id.isGxsId()) { - peer_id = RsPeerId(chat_id.toGxsId()); + if (chat_id.isDistantChatId()) { + peer_id = RsPeerId(chat_id.toDistantChatId()); return true; } @@ -436,7 +433,7 @@ bool p3HistoryMgr::getMessages(const ChatId &chatId, std::list &msgs if (chatId.isLobbyId() && mLobbyEnable == true) { enabled = true; } - if (chatId.isGxsId() && mPrivateEnable == true) { + if (chatId.isDistantChatId() && mPrivateEnable == true) { enabled = true; } diff --git a/libretroshare/src/retroshare/rsgxstunnel.h b/libretroshare/src/retroshare/rsgxstunnel.h index 90499758c..6263c30e5 100644 --- a/libretroshare/src/retroshare/rsgxstunnel.h +++ b/libretroshare/src/retroshare/rsgxstunnel.h @@ -33,16 +33,20 @@ class RsGxsTunnelService { public: - static const uint32_t RS_GXS_TUNNEL_ERROR_NO_ERROR = 0x0000 ; - static const uint32_t RS_GXS_TUNNEL_ERROR_UNKNOWN_GXS_ID = 0x0001 ; - - static const uint32_t RS_GXS_TUNNEL_STATUS_UNKNOWN = 0x00 ; - static const uint32_t RS_GXS_TUNNEL_STATUS_CAN_TALK = 0x01 ; - static const uint32_t RS_GXS_TUNNEL_STATUS_TUNNEL_DN = 0x02 ; - static const uint32_t RS_GXS_TUNNEL_STATUS_REMOTELY_CLOSED = 0x03 ; - typedef GXSTunnelId RsGxsTunnelId ; + enum { + RS_GXS_TUNNEL_ERROR_NO_ERROR = 0x0000, + RS_GXS_TUNNEL_ERROR_UNKNOWN_GXS_ID = 0x0001 + }; + + enum { + RS_GXS_TUNNEL_STATUS_UNKNOWN = 0x00, + RS_GXS_TUNNEL_STATUS_TUNNEL_DN = 0x01, + RS_GXS_TUNNEL_STATUS_CAN_TALK = 0x02, + RS_GXS_TUNNEL_STATUS_REMOTELY_CLOSED = 0x03 + }; + class RsGxsTunnelClientService { public: @@ -102,8 +106,9 @@ public: // Asks for a tunnel. The service will request it to turtle router, and exchange a AES key using DH. // When the tunnel is secured, the client---here supplied as argument---will be notified. He can // then send data into the tunnel. The same tunnel may be used by different clients. + // The service id is passed on so that the client is notified when the tunnel is up. - virtual bool requestSecuredTunnel(const RsGxsId& to_id,const RsGxsId& from_id,RsGxsTunnelId& tunnel_id,uint32_t& error_code) =0 ; + virtual bool requestSecuredTunnel(const RsGxsId& to_id,const RsGxsId& from_id,RsGxsTunnelId& tunnel_id,uint32_t service_id,uint32_t& error_code) =0 ; // Data is sent through the established tunnel, possibly multiple times, until reception is acknowledged. If the tunnel does not exist, the item is rejected and // an error is issued. In any case, the memory ownership of the data is *not* transferred to the tunnel service, so the client should delete it afterwards, if needed. @@ -113,7 +118,7 @@ public: // Removes any established tunnel to this GXS id. This makes the tunnel refuse further data, but the tunnel will be however kept alive // until all pending data is flushed. All clients attached to the tunnel will be notified that the tunnel gets closed. - virtual bool closeExistingTunnel(const RsGxsTunnelId& to_id) =0; + virtual bool closeExistingTunnel(const RsGxsTunnelId& to_id,uint32_t service_id) =0; //===================================================// // Routage feedback from other services // diff --git a/libretroshare/src/retroshare/rsids.h b/libretroshare/src/retroshare/rsids.h index 6893e8c11..6cd97f5ad 100644 --- a/libretroshare/src/retroshare/rsids.h +++ b/libretroshare/src/retroshare/rsids.h @@ -209,16 +209,17 @@ static const int SHA1_SIZE = 20 ; // These constants are random, but should be different, in order to make the various IDs incompatible with each other. // -static const uint32_t RS_GENERIC_ID_SSL_ID_TYPE = 0x0001 ; -static const uint32_t RS_GENERIC_ID_PGP_ID_TYPE = 0x0002 ; -static const uint32_t RS_GENERIC_ID_SHA1_ID_TYPE = 0x0003 ; -static const uint32_t RS_GENERIC_ID_PGP_FINGERPRINT_TYPE = 0x0004 ; -static const uint32_t RS_GENERIC_ID_GXS_GROUP_ID_TYPE = 0x0005 ; -static const uint32_t RS_GENERIC_ID_GXS_ID_TYPE = 0x0006 ; -static const uint32_t RS_GENERIC_ID_GXS_MSG_ID_TYPE = 0x0007 ; -static const uint32_t RS_GENERIC_ID_GXS_CIRCLE_ID_TYPE = 0x0008 ; -static const uint32_t RS_GENERIC_ID_GROUTER_ID_TYPE = 0x0009 ; -static const uint32_t RS_GENERIC_ID_GXS_TUNNEL_ID_TYPE = 0x0010 ; +static const uint32_t RS_GENERIC_ID_SSL_ID_TYPE = 0x0001 ; +static const uint32_t RS_GENERIC_ID_PGP_ID_TYPE = 0x0002 ; +static const uint32_t RS_GENERIC_ID_SHA1_ID_TYPE = 0x0003 ; +static const uint32_t RS_GENERIC_ID_PGP_FINGERPRINT_TYPE = 0x0004 ; +static const uint32_t RS_GENERIC_ID_GXS_GROUP_ID_TYPE = 0x0005 ; +static const uint32_t RS_GENERIC_ID_GXS_ID_TYPE = 0x0006 ; +static const uint32_t RS_GENERIC_ID_GXS_MSG_ID_TYPE = 0x0007 ; +static const uint32_t RS_GENERIC_ID_GXS_CIRCLE_ID_TYPE = 0x0008 ; +static const uint32_t RS_GENERIC_ID_GROUTER_ID_TYPE = 0x0009 ; +static const uint32_t RS_GENERIC_ID_GXS_TUNNEL_ID_TYPE = 0x0010 ; +static const uint32_t RS_GENERIC_ID_GXS_DISTANT_CHAT_ID_TYPE = 0x0011 ; typedef t_RsGenericIdType< SSL_ID_SIZE , false, RS_GENERIC_ID_SSL_ID_TYPE> SSLIdType ; typedef t_RsGenericIdType< PGP_KEY_ID_SIZE , true, RS_GENERIC_ID_PGP_ID_TYPE> PGPIdType ; @@ -229,4 +230,5 @@ typedef t_RsGenericIdType< CERT_SIGN_LEN , false, RS_GENERIC_ID_GXS_G typedef t_RsGenericIdType< CERT_SIGN_LEN , false, RS_GENERIC_ID_GXS_ID_TYPE > GXSId ; typedef t_RsGenericIdType< CERT_SIGN_LEN , false, RS_GENERIC_ID_GXS_CIRCLE_ID_TYPE > GXSCircleId ; typedef t_RsGenericIdType< SSL_ID_SIZE , false, RS_GENERIC_ID_GXS_TUNNEL_ID_TYPE > GXSTunnelId ; +typedef t_RsGenericIdType< SSL_ID_SIZE , false, RS_GENERIC_ID_GXS_DISTANT_CHAT_ID_TYPE > DistantChatPeerId ; diff --git a/libretroshare/src/retroshare/rsmsgs.h b/libretroshare/src/retroshare/rsmsgs.h index 793ed20be..4eadb79d1 100644 --- a/libretroshare/src/retroshare/rsmsgs.h +++ b/libretroshare/src/retroshare/rsmsgs.h @@ -99,8 +99,6 @@ typedef uint64_t ChatLobbyId ; typedef uint64_t ChatLobbyMsgId ; typedef std::string ChatLobbyNickName ; -typedef RsPeerId DistantChatPeerId ; - typedef uint64_t MessageId ; @@ -254,10 +252,8 @@ public: #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_STATUS_REMOTELY_CLOSED 0x0004 -#define RS_DISTANT_CHAT_STATUS_WAITING_DH 0x0005 +#define RS_DISTANT_CHAT_STATUS_CAN_TALK 0x0002 +#define RS_DISTANT_CHAT_STATUS_REMOTELY_CLOSED 0x0003 #define RS_DISTANT_CHAT_ERROR_NO_ERROR 0x0000 #define RS_DISTANT_CHAT_ERROR_DECRYPTION_FAILED 0x0001 @@ -285,6 +281,7 @@ public: explicit ChatId(RsPeerId id); explicit ChatId(RsGxsId id); explicit ChatId(ChatLobbyId id); + explicit ChatId(DistantChatPeerId id); explicit ChatId(std::string str); static ChatId makeBroadcastId(); @@ -296,13 +293,15 @@ public: bool isNotSet() const; bool isPeerId() const; - bool isGxsId() const; + bool isDistantChatId() const; bool isLobbyId() const; + bool isGxsId() const; bool isBroadcast() const; RsPeerId toPeerId() const; RsGxsId toGxsId() const; ChatLobbyId toLobbyId() const; + DistantChatPeerId toDistantChatId() const; // for the very specific case of transfering a status string // from the chatservice to the gui, @@ -313,13 +312,15 @@ private: TYPE_PRIVATE, // private chat with directly connected friend, peer_id is valid TYPE_PRIVATE_DISTANT, // private chat with distant peer, gxs_id is valid TYPE_LOBBY, // chat lobby id, lobby_id is valid + TYPE_GXS_ID, // TYPE_BROADCAST // message to/from all connected peers }; Type type; RsPeerId peer_id; - RsGxsId gxs_id; + DistantChatPeerId distant_chat_id; ChatLobbyId lobby_id; + RsGxsId gxs_id; }; class ChatMessage diff --git a/libretroshare/src/rsserver/p3msgs.cc b/libretroshare/src/rsserver/p3msgs.cc index 8d52fcc8b..b9690c95d 100644 --- a/libretroshare/src/rsserver/p3msgs.cc +++ b/libretroshare/src/rsserver/p3msgs.cc @@ -58,6 +58,13 @@ ChatId::ChatId(): } +ChatId::ChatId(RsGxsId id): + lobby_id(0) +{ + type = TYPE_GXS_ID; + gxs_id = id; +} + ChatId::ChatId(RsPeerId id): lobby_id(0) { @@ -65,11 +72,11 @@ ChatId::ChatId(RsPeerId id): peer_id = id; } -ChatId::ChatId(RsGxsId id): +ChatId::ChatId(DistantChatPeerId id): lobby_id(0) { type = TYPE_PRIVATE_DISTANT; - gxs_id = id; + distant_chat_id = id; } ChatId::ChatId(ChatLobbyId id): @@ -93,7 +100,7 @@ ChatId::ChatId(std::string str): else if(str[0] == 'D') { type = TYPE_PRIVATE_DISTANT; - gxs_id == GXSId(str.substr(1)); + distant_chat_id == DistantChatPeerId(str.substr(1)); } else if(str[0] == 'L') { @@ -143,7 +150,7 @@ std::string ChatId::toStdString() const else if(type == TYPE_PRIVATE_DISTANT) { str += "D"; - str += gxs_id.toStdString(); + str += distant_chat_id.toStdString(); } else if(type == TYPE_LOBBY) { @@ -186,7 +193,7 @@ bool ChatId::operator <(const ChatId& other) const case TYPE_PRIVATE: return peer_id < other.peer_id; case TYPE_PRIVATE_DISTANT: - return gxs_id < other.gxs_id; + return distant_chat_id < other.distant_chat_id; case TYPE_LOBBY: return lobby_id < other.lobby_id; case TYPE_BROADCAST: @@ -210,7 +217,7 @@ bool ChatId::isSameEndpoint(const ChatId &other) const case TYPE_PRIVATE: return peer_id == other.peer_id; case TYPE_PRIVATE_DISTANT: - return gxs_id == other.gxs_id; + return distant_chat_id == other.distant_chat_id; case TYPE_LOBBY: return lobby_id == other.lobby_id; case TYPE_BROADCAST: @@ -229,7 +236,7 @@ bool ChatId::isPeerId() const { return type == TYPE_PRIVATE; } -bool ChatId::isGxsId() const +bool ChatId::isDistantChatId() const { return type == TYPE_PRIVATE_DISTANT; } @@ -237,6 +244,10 @@ bool ChatId::isLobbyId() const { return type == TYPE_LOBBY; } +bool ChatId::isGxsId() const +{ + return type == TYPE_GXS_ID; +} bool ChatId::isBroadcast() const { return type == TYPE_BROADCAST; @@ -251,16 +262,27 @@ RsPeerId ChatId::toPeerId() const return RsPeerId(); } } + RsGxsId ChatId::toGxsId() const { - if(type == TYPE_PRIVATE_DISTANT) + if(type == TYPE_GXS_ID) return gxs_id; else { - std::cerr << "ChatId Warning: conversation to RsGxsId requested, but type is different. Current value=\"" << toStdString() << "\"" << std::endl; + std::cerr << "ChatId Warning: conversation to gxs_id requested, but type is different. Current value=\"" << toStdString() << "\"" << std::endl; return RsGxsId(); } } +DistantChatPeerId ChatId::toDistantChatId() const +{ + if(type == TYPE_PRIVATE_DISTANT) + return distant_chat_id; + else + { + std::cerr << "ChatId Warning: conversation to DistantChatPeerId requested, but type is different. Current value=\"" << toStdString() << "\"" << std::endl; + return DistantChatPeerId(); + } +} ChatLobbyId ChatId::toLobbyId() const { if(type == TYPE_LOBBY) diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index 684f08998..6422bc1f4 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -266,7 +266,7 @@ bool doPortRestrictions = false; /******************************** WINDOWS/UNIX SPECIFIC PART ******************/ #ifndef WINDOWS_SYS -int RsInit::InitRetroShare(int argc, char **argv, bool strictCheck) +int RsInit::InitRetroShare(int argc, char **argv, bool /* strictCheck */) { /******************************** WINDOWS/UNIX SPECIFIC PART ******************/ #else diff --git a/libretroshare/src/services/p3gxschannels.cc b/libretroshare/src/services/p3gxschannels.cc index afd4c1ef6..580cd5467 100644 --- a/libretroshare/src/services/p3gxschannels.cc +++ b/libretroshare/src/services/p3gxschannels.cc @@ -122,7 +122,7 @@ uint32_t p3GxsChannels::channelsAuthenPolicy() /** Overloaded to cache new groups **/ -RsGenExchange::ServiceCreate_Return p3GxsChannels::service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySet& keySet) +RsGenExchange::ServiceCreate_Return p3GxsChannels::service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySet& /* keySet */) { updateSubscribedGroup(grpItem->meta); return SERVICE_CREATE_SUCCESS; diff --git a/libretroshare/src/upnp/upnphandler_linux.h b/libretroshare/src/upnp/upnphandler_linux.h index b0300dfc9..b22a9a9e2 100644 --- a/libretroshare/src/upnp/upnphandler_linux.h +++ b/libretroshare/src/upnp/upnphandler_linux.h @@ -40,8 +40,8 @@ class upnphandler: public pqiNetAssistFirewall virtual bool getExternalAddress(struct sockaddr_storage &addr); /* TO IMPLEMENT: New Port Forward interface to support as many ports as necessary */ - virtual bool requestPortForward(const PortForwardParams ¶ms) { return false; } - virtual bool statusPortForward(const uint32_t fwdId, PortForwardParams ¶ms) { return false; } + virtual bool requestPortForward(const PortForwardParams & /* params */) { return false; } + virtual bool statusPortForward(const uint32_t /* fwdId */, PortForwardParams & /*params*/) { return false; } /* Public functions - for background thread operation, * but effectively private from rest of RS, as in derived class diff --git a/retroshare-gui/src/gui/chat/ChatDialog.cpp b/retroshare-gui/src/gui/chat/ChatDialog.cpp index 6175cb8ad..2ab8b8e90 100644 --- a/retroshare-gui/src/gui/chat/ChatDialog.cpp +++ b/retroshare-gui/src/gui/chat/ChatDialog.cpp @@ -93,11 +93,10 @@ void ChatDialog::init(ChatId id, const QString &title) /* see if it already exists */ ChatDialog *cd = getExistingChat(id); - DistantChatPeerInfo pinfo ; if (cd == NULL) { - if(id.isGxsId()) + if(id.isDistantChatId()) chatflags = RS_CHAT_OPEN | RS_CHAT_FOCUS; // force open for distant chat if (chatflags & RS_CHAT_OPEN) { @@ -106,10 +105,11 @@ void ChatDialog::init(ChatId id, const QString &title) cld->init(); cd = cld; } - else if(id.isPeerId() && rsMsgs->getDistantChatStatus(id.toPeerId(),pinfo)) + else if(id.isDistantChatId()) { - PopupDistantChatDialog* pdcd = new PopupDistantChatDialog(id.toPeerId()); - pdcd->init(pinfo.peer_id, QString("This is a distant chat")) ; + PopupDistantChatDialog* pdcd = new PopupDistantChatDialog(id.toDistantChatId()); + + pdcd->init(id.toDistantChatId()); cd = pdcd; } else @@ -172,7 +172,7 @@ void ChatDialog::init(ChatId id, const QString &title) if(msg.chat_id.isBroadcast()) return; // broadcast is not handled by a chat dialog - if(msg.incoming && (msg.chat_id.isPeerId() || msg.chat_id.isGxsId())) + if(msg.incoming && (msg.chat_id.isPeerId() || msg.chat_id.isDistantChatId())) // play sound when recv a message SoundManager::play(SOUND_NEW_CHAT_MESSAGE); @@ -338,8 +338,8 @@ void ChatDialog::setPeerStatus(uint32_t status) RsPeerId vpid; if(mChatId.isPeerId()) vpid = mChatId.toPeerId(); - if(mChatId.isGxsId()) - vpid = RsPeerId(mChatId.toGxsId()); + if(mChatId.isDistantChatId()) + vpid = RsPeerId(mChatId.toDistantChatId()); cw->updateStatus(QString::fromStdString(vpid.toStdString()), status); } } diff --git a/retroshare-gui/src/gui/chat/ChatUserNotify.cpp b/retroshare-gui/src/gui/chat/ChatUserNotify.cpp index 9aed09807..1bc4a1df9 100644 --- a/retroshare-gui/src/gui/chat/ChatUserNotify.cpp +++ b/retroshare-gui/src/gui/chat/ChatUserNotify.cpp @@ -109,7 +109,7 @@ void ChatUserNotify::chatMessageReceived(ChatMessage msg) if(!msg.chat_id.isBroadcast() &&( ChatDialog::getExistingChat(msg.chat_id) || (Settings->getChatFlags() & RS_CHAT_OPEN) - || msg.chat_id.isGxsId())) + || msg.chat_id.isDistantChatId())) { ChatDialog::chatMessageReceived(msg); } diff --git a/retroshare-gui/src/gui/chat/ChatWidget.cpp b/retroshare-gui/src/gui/chat/ChatWidget.cpp index 42344c4c8..12667f03e 100644 --- a/retroshare-gui/src/gui/chat/ChatWidget.cpp +++ b/retroshare-gui/src/gui/chat/ChatWidget.cpp @@ -249,7 +249,7 @@ void ChatWidget::init(const ChatId &chat_id, const QString &title) RsPeerId ownId = rsPeers->getOwnId(); setName(QString::fromUtf8(rsPeers->getPeerName(ownId).c_str())); - if(chatId.isPeerId() || chatId.isGxsId()) + if(chatId.isPeerId() || chatId.isDistantChatId()) chatStyle.setStyleFromSettings(ChatStyle::TYPE_PRIVATE); if(chatId.isBroadcast() || chatId.isLobbyId()) chatStyle.setStyleFromSettings(ChatStyle::TYPE_PUBLIC); @@ -328,7 +328,8 @@ void ChatWidget::init(const ChatId &chat_id, const QString &title) continue; QString name; - if (chatId.isLobbyId() || chatId.isGxsId()) { + if (chatId.isLobbyId() || chatId.isDistantChatId()) + { RsIdentityDetails details; if (rsIdentity->getIdDetails(RsGxsId(historyIt->peerName), details)) name = QString::fromUtf8(details.mNickname.c_str()); @@ -360,7 +361,7 @@ ChatWidget::ChatType ChatWidget::chatType() // but maybe it is good to have separate types in libretroshare and gui if(chatId.isPeerId()) return CHATTYPE_PRIVATE; - if(chatId.isGxsId()) + if(chatId.isDistantChatId()) return CHATTYPE_DISTANT; if(chatId.isLobbyId()) return CHATTYPE_LOBBY; @@ -1501,77 +1502,83 @@ void ChatWidget::updateStatus(const QString &peer_id, int status) // make virtual peer id from gxs id in case of distant chat RsPeerId vpid; - if(chatId.isGxsId()) - vpid = RsPeerId(chatId.toGxsId()); + if(chatId.isDistantChatId()) + vpid = RsPeerId(chatId.toDistantChatId()); else vpid = chatId.toPeerId(); /* set font size for status */ - if (peer_id.toStdString() == vpid.toStdString()) { - // the peers status has changed + if (peer_id.toStdString() == vpid.toStdString()) + { + // the peers status has changed - QString peerName ; - if(chatId.isGxsId()) - { - RsIdentityDetails details ; - if(rsIdentity->getIdDetails(chatId.toGxsId(),details)) - peerName = QString::fromUtf8( details.mNickname.c_str() ) ; - else - peerName = QString::fromStdString(chatId.toGxsId().toStdString()) ; - } - else - peerName = QString::fromUtf8(rsPeers->getPeerName(chatId.toPeerId()).c_str()); + QString peerName ; + if(chatId.isDistantChatId()) + { + DistantChatPeerInfo dcpinfo ; + RsIdentityDetails details ; - // is scrollbar at the end? - QScrollBar *scrollbar = ui->textBrowser->verticalScrollBar(); - bool atEnd = (scrollbar->value() == scrollbar->maximum()); + if(rsMsgs->getDistantChatStatus(chatId.toDistantChatId(),dcpinfo)) + if(rsIdentity->getIdDetails(dcpinfo.to_id,details)) + peerName = QString::fromUtf8( details.mNickname.c_str() ) ; + else + peerName = QString::fromStdString(dcpinfo.to_id.toStdString()) ; + else + peerName = QString::fromStdString(chatId.toDistantChatId().toStdString()) ; + } + else + peerName = QString::fromUtf8(rsPeers->getPeerName(chatId.toPeerId()).c_str()); - switch (status) { - case RS_STATUS_OFFLINE: - ui->infoFrame->setVisible(true); - ui->infoLabel->setText(peerName + " " + tr("appears to be Offline.") +"\n" + tr("Messages you send will be delivered after Friend is again Online")); - break; + // is scrollbar at the end? + QScrollBar *scrollbar = ui->textBrowser->verticalScrollBar(); + bool atEnd = (scrollbar->value() == scrollbar->maximum()); - case RS_STATUS_INACTIVE: - ui->infoFrame->setVisible(true); - ui->infoLabel->setText(peerName + " " + tr("is Idle and may not reply")); - break; + switch (status) { + case RS_STATUS_OFFLINE: + ui->infoFrame->setVisible(true); + ui->infoLabel->setText(peerName + " " + tr("appears to be Offline.") +"\n" + tr("Messages you send will be delivered after Friend is again Online")); + break; - case RS_STATUS_ONLINE: - ui->infoFrame->setVisible(false); - break; + case RS_STATUS_INACTIVE: + ui->infoFrame->setVisible(true); + ui->infoLabel->setText(peerName + " " + tr("is Idle and may not reply")); + break; - case RS_STATUS_AWAY: - ui->infoLabel->setText(peerName + " " + tr("is Away and may not reply")); - ui->infoFrame->setVisible(true); - break; + case RS_STATUS_ONLINE: + ui->infoFrame->setVisible(false); + break; - case RS_STATUS_BUSY: - ui->infoLabel->setText(peerName + " " + tr("is Busy and may not reply")); - ui->infoFrame->setVisible(true); - break; - } + case RS_STATUS_AWAY: + ui->infoLabel->setText(peerName + " " + tr("is Away and may not reply")); + ui->infoFrame->setVisible(true); + break; - ui->titleLabel->setText(peerName); - ui->statusLabel->setText(QString("(%1)").arg(StatusDefs::name(status))); + case RS_STATUS_BUSY: + ui->infoLabel->setText(peerName + " " + tr("is Busy and may not reply")); + ui->infoFrame->setVisible(true); + break; + } - peerStatus = status; + ui->titleLabel->setText(peerName); + ui->statusLabel->setText(QString("(%1)").arg(StatusDefs::name(status))); - if (atEnd) { - // scroll to the end - scrollbar->setValue(scrollbar->maximum()); - } + peerStatus = status; - emit infoChanged(this); - emit statusChanged(status); + if (atEnd) { + // scroll to the end + scrollbar->setValue(scrollbar->maximum()); + } - // Notify all ChatWidgetHolder - foreach (ChatWidgetHolder *chatWidgetHolder, mChatWidgetHolder) { - chatWidgetHolder->updateStatus(status); - } + emit infoChanged(this); + emit statusChanged(status); - return; - } + // Notify all ChatWidgetHolder + foreach (ChatWidgetHolder *chatWidgetHolder, mChatWidgetHolder) { + chatWidgetHolder->updateStatus(status); + } + + return; + } // ignore status change } diff --git a/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp b/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp index 966946616..0aa3c0657 100644 --- a/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp +++ b/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp @@ -60,7 +60,7 @@ PopupDistantChatDialog::PopupDistantChatDialog(const DistantChatPeerId& tunnel_i updateDisplay() ; } -void PopupDistantChatDialog::init(const DistantChatPeerId &peer_id, const QString &title) +void PopupDistantChatDialog::init(const DistantChatPeerId &peer_id) { _tunnel_id = peer_id; DistantChatPeerInfo tinfo; @@ -68,12 +68,18 @@ void PopupDistantChatDialog::init(const DistantChatPeerId &peer_id, const QStrin if(!rsMsgs->getDistantChatStatus(_tunnel_id,tinfo)) return ; - PopupChatDialog::init(ChatId(tinfo.to_id), title) ; + RsIdentityDetails iddetails ; + + if(rsIdentity->getIdDetails(tinfo.to_id,iddetails)) + PopupChatDialog::init(ChatId(peer_id), QString::fromUtf8(iddetails.mNickname.c_str())) ; + else + PopupChatDialog::init(ChatId(peer_id), QString::fromStdString(tinfo.to_id.toStdString())) ; // Do not use setOwnId, because we don't want the user to change the GXS avatar from the chat window // it will not be transmitted. - ui.ownAvatarWidget->setId(ChatId(tinfo.own_id)); + ui.ownAvatarWidget->setOwnId() ; // sets the flag + ui.ownAvatarWidget->setId(ChatId(peer_id)) ; // sets the actual Id } void PopupDistantChatDialog::updateDisplay() @@ -91,7 +97,7 @@ void PopupDistantChatDialog::updateDisplay() DistantChatPeerInfo tinfo; rsMsgs->getDistantChatStatus(_tunnel_id,tinfo) ; - ui.avatarWidget->setId(ChatId(tinfo.to_id)); + ui.avatarWidget->setId(ChatId(_tunnel_id)); QString msg; switch(tinfo.status) diff --git a/retroshare-gui/src/gui/chat/PopupDistantChatDialog.h b/retroshare-gui/src/gui/chat/PopupDistantChatDialog.h index 85a9144e4..e0d00b7f3 100644 --- a/retroshare-gui/src/gui/chat/PopupDistantChatDialog.h +++ b/retroshare-gui/src/gui/chat/PopupDistantChatDialog.h @@ -38,7 +38,7 @@ class PopupDistantChatDialog: public PopupChatDialog /** Default destructor */ virtual ~PopupDistantChatDialog(); - virtual void init(const DistantChatPeerId& peer_id, const QString &title); + virtual void init(const DistantChatPeerId& peer_id); virtual void closeEvent(QCloseEvent *e) ; virtual QString getPeerName(const ChatId &id) const ; diff --git a/retroshare-gui/src/gui/common/AvatarWidget.cpp b/retroshare-gui/src/gui/common/AvatarWidget.cpp index 8a888c884..2ed494184 100644 --- a/retroshare-gui/src/gui/common/AvatarWidget.cpp +++ b/retroshare-gui/src/gui/common/AvatarWidget.cpp @@ -124,8 +124,6 @@ void AvatarWidget::setFrameType(FrameType type) void AvatarWidget::setId(const ChatId &id) { mId = id; -// mPgpId = rsPeers->getGPGId(id) ; -// mFlag.isGpg = false ; setPixmap(QPixmap()); @@ -133,15 +131,12 @@ void AvatarWidget::setId(const ChatId &id) setEnabled(false); } + if(mId.isGxsId()) + std::cerr << "(EE) AvatarWidget should not be set to a GXS id." << std::endl; + refreshAvatarImage(); refreshStatus(); } -void AvatarWidget::setOwnId(const RsGxsId& own_gxs_id) -{ - mFlag.isOwnId = true; - - setId(ChatId(own_gxs_id)); -} void AvatarWidget::setOwnId() { mFlag.isOwnId = true; @@ -181,7 +176,7 @@ void AvatarWidget::refreshStatus() rsStatus->getOwnStatus(statusInfo); status = statusInfo.status ; } - else if(mId.isGxsId()) + else if(mId.isDistantChatId()) status = RS_STATUS_ONLINE ; else { @@ -198,12 +193,15 @@ void AvatarWidget::refreshStatus() rsStatus->getStatus(mId.toPeerId(), statusInfo); status = statusInfo.status ; } - else if(mId.isGxsId()) - { -//if(!rsMsgs->getDistantChatStatus(mId.toGxsId(),status)) - status = RS_STATUS_OFFLINE ; -#warning we need to do something clever here - } + else if(mId.isDistantChatId()) + { + DistantChatPeerInfo dcpinfo ; + + if(rsMsgs->getDistantChatStatus(mId.toDistantChatId(),dcpinfo)) + status = dcpinfo.status ; + else + std::cerr << "(EE) cannot get distant chat status for ID=" << mId.toDistantChatId() << std::endl; + } else { std::cerr << "Unhandled chat id type in AvatarWidget::refreshStatus()" << std::endl; @@ -236,10 +234,11 @@ void AvatarWidget::updateStatus(int status) void AvatarWidget::updateAvatar(const QString &peerId) { if(mId.isPeerId() && mId.toPeerId() == RsPeerId(peerId.toStdString())) - refreshAvatarImage() ; - - if(mId.isGxsId() && mId.toGxsId() == RsGxsId(peerId.toStdString())) - refreshAvatarImage() ; + refreshAvatarImage() ; + else if(mId.isDistantChatId() && mId.toDistantChatId() == DistantChatPeerId(peerId.toStdString())) + refreshAvatarImage() ; + else + std::cerr << "(EE) cannot update avatar. mId has unhandled type." << std::endl; } void AvatarWidget::refreshAvatarImage() { @@ -263,12 +262,29 @@ void AvatarWidget::refreshAvatarImage() setPixmap(avatar); return; } - else if (mId.isGxsId()) +// else if (mId.isGxsId()) +// { +// QPixmap avatar; +// +// AvatarDefs::getAvatarFromGxsId(mId.toGxsId(), avatar, defaultAvatar); +// setPixmap(avatar); +// return; +// } + else if (mId.isDistantChatId()) { - QPixmap avatar; - AvatarDefs::getAvatarFromGxsId(mId.toGxsId(), avatar, defaultAvatar); - setPixmap(avatar); - return; + QPixmap avatar; + + DistantChatPeerInfo dcpinfo ; + + if(rsMsgs->getDistantChatStatus(mId.toDistantChatId(),dcpinfo)) + { + if(mFlag.isOwnId) + AvatarDefs::getAvatarFromGxsId(dcpinfo.own_id, avatar, defaultAvatar); + else + AvatarDefs::getAvatarFromGxsId(dcpinfo.to_id, avatar, defaultAvatar); + setPixmap(avatar); + return; + } } else std::cerr << "WARNING: unhandled situation in AvatarWidget::refreshAvatarImage()" << std::endl; diff --git a/retroshare-gui/src/gui/common/AvatarWidget.h b/retroshare-gui/src/gui/common/AvatarWidget.h index 61db1bada..1c140f469 100644 --- a/retroshare-gui/src/gui/common/AvatarWidget.h +++ b/retroshare-gui/src/gui/common/AvatarWidget.h @@ -51,7 +51,6 @@ public: void setFrameType(FrameType type); void setId(const ChatId& id) ; void setOwnId(); - void setOwnId(const RsGxsId&); void setDefaultAvatar(const QString &avatar_file_name); protected: diff --git a/retroshare-gui/src/gui/im_history/ImHistoryBrowser.cpp b/retroshare-gui/src/gui/im_history/ImHistoryBrowser.cpp index f2d15a8c6..a107f82da 100644 --- a/retroshare-gui/src/gui/im_history/ImHistoryBrowser.cpp +++ b/retroshare-gui/src/gui/im_history/ImHistoryBrowser.cpp @@ -116,7 +116,7 @@ ImHistoryBrowser::ImHistoryBrowser(const ChatId &chatId, QTextEdit *edit, QWidge ui.filterLineEdit->showFilterIcon(); // embed smileys ? - if (m_chatId.isPeerId() || m_chatId.isGxsId()) { + if (m_chatId.isPeerId() || m_chatId.isDistantChatId()) { embedSmileys = Settings->valueFromGroup("Chat", "Emoteicons_PrivatChat", true).toBool(); } else { embedSmileys = Settings->valueFromGroup("Chat", "Emoteicons_GroupChat", true).toBool(); @@ -275,7 +275,7 @@ void ImHistoryBrowser::fillItem(QListWidgetItem *itemWidget, HistoryMsg& msg) QString messageText = RsHtml().formatText(NULL, QString::fromUtf8(msg.message.c_str()), formatTextFlag); QString name; - if (m_chatId.isLobbyId() || m_chatId.isGxsId()) { + if (m_chatId.isLobbyId() || m_chatId.isDistantChatId()) { RsIdentityDetails details; if (rsIdentity->getIdDetails(RsGxsId(msg.peerName), details)) name = QString::fromUtf8(details.mNickname.c_str()); diff --git a/retroshare-gui/src/gui/settings/RsharePeerSettings.cpp b/retroshare-gui/src/gui/settings/RsharePeerSettings.cpp index d01d494a8..05dae3e17 100644 --- a/retroshare-gui/src/gui/settings/RsharePeerSettings.cpp +++ b/retroshare-gui/src/gui/settings/RsharePeerSettings.cpp @@ -112,7 +112,7 @@ bool RsharePeerSettings::getSettingsIdOfPeerId(const ChatId& chatId, std::string m_SslToGpg[peerId] = settingsId ; return true; } - if(chatId.isGxsId() || chatId.isLobbyId() || chatId.isBroadcast()) + if(chatId.isDistantChatId() || chatId.isLobbyId() || chatId.isBroadcast()) { settingsId = chatId.toStdString(); return true; From 12866cd73521774bbac22654b43650bdf30b065f Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 30 Nov 2015 20:51:47 -0500 Subject: [PATCH 15/26] fixed a few bugs in new distant chat --- libretroshare/src/chat/distantchat.cc | 2 ++ libretroshare/src/gxstunnel/p3gxstunnel.cc | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/libretroshare/src/chat/distantchat.cc b/libretroshare/src/chat/distantchat.cc index eee035197..e311b9233 100644 --- a/libretroshare/src/chat/distantchat.cc +++ b/libretroshare/src/chat/distantchat.cc @@ -157,6 +157,8 @@ void DistantChatService::receiveData(const RsGxsTunnelService::RsGxsTunnelId &tu if(item != NULL) { + item->PeerId(RsPeerId(tunnel_id)) ; // just in case, but normally this is already done. + handleIncomingItem(item) ; RsServer::notify()->notifyListChange(NOTIFY_LIST_PRIVATE_INCOMING_CHAT, NOTIFY_TYPE_ADD); } diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.cc b/libretroshare/src/gxstunnel/p3gxstunnel.cc index 2460bb9aa..af333ad45 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.cc +++ b/libretroshare/src/gxstunnel/p3gxstunnel.cc @@ -896,6 +896,7 @@ void p3GxsTunnelService::handleRecvDHPublicKey(RsGxsTunnelDHPublicKeyItem *item) pinfo.virtual_peer_id = vpid ; pinfo.direction = it->second.direction ; pinfo.own_gxs_id = own_id ; + pinfo.to_gxs_id = item->signature.keyId; // this is already set for client side but not for server side. // note: the hash might still be nn initialised on server side. @@ -1433,7 +1434,7 @@ bool p3GxsTunnelService::closeExistingTunnel(const RsGxsTunnelId& tunnel_id, uin RsGxsTunnelStatusItem *cs = new RsGxsTunnelStatusItem ; cs->status = RS_GXS_TUNNEL_FLAG_CLOSING_DISTANT_CONNECTION; - cs->PeerId(vpid) ; + cs->PeerId(RsPeerId(tunnel_id)) ; locked_sendEncryptedTunnelData(cs) ; // that needs to be done off-mutex and before we close the tunnel also ignoring failure. From 266652f70eef884f1a7ea1737fd22cd53ad8c004 Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 30 Nov 2015 21:02:12 -0500 Subject: [PATCH 16/26] put ifdefs around debug info in tunnel service --- libretroshare/src/gxstunnel/p3gxstunnel.cc | 52 +++++++++++++++++++++- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.cc b/libretroshare/src/gxstunnel/p3gxstunnel.cc index af333ad45..36442d978 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.cc +++ b/libretroshare/src/gxstunnel/p3gxstunnel.cc @@ -93,8 +93,9 @@ bool p3GxsTunnelService::registerClientService(uint32_t service_id,RsGxsTunnelSe std::cerr << "(EE) p3GxsTunnelService::registerClientService(): trying to register client " << std::hex << service_id << std::dec << ", which is already registered!" << std::endl; return false; } - +#ifdef DEBUG_GXS_TUNNEL std::cerr << "p3GxsTunnelService::registerClientService(): registering client service " << std::hex << service_id << std::dec << std::endl; +#endif mRegisteredServices[service_id] = service ; return true ; @@ -103,7 +104,8 @@ bool p3GxsTunnelService::registerClientService(uint32_t service_id,RsGxsTunnelSe int p3GxsTunnelService::tick() { static time_t last_dump = 0 ; - std::cerr << "p3GxsTunnelService::tick()" << std::endl; + +#ifdef DEBUG_GXS_TUNNEL time_t now = time(NULL); if(now > last_dump + INTERVAL_BETWEEN_DEBUG_DUMP ) @@ -111,6 +113,7 @@ int p3GxsTunnelService::tick() last_dump = now ; debug_dump() ; } +#endif flush() ; @@ -131,7 +134,9 @@ void p3GxsTunnelService::flush() { // Flush pending DH items. This is a higher priority, so we deal with them first. +#ifdef DEBUG_GXS_TUNNEL std::cerr << "p3GxsTunnelService::flush() flushing pending items." << std::endl; +#endif { RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ @@ -148,8 +153,10 @@ void p3GxsTunnelService::flush() while(!pendingGxsTunnelItems.empty()) if(locked_sendEncryptedTunnelData(pendingGxsTunnelItems.front())) pendingGxsTunnelItems.pop_front() ; +#ifdef DEBUG_GXS_TUNNEL else std::cerr << "Cannot send encrypted data item to tunnel " << pendingGxsTunnelItems.front()->PeerId() << std::endl; +#endif } // Look at pending data item, and re-send them if necessary. @@ -164,11 +171,15 @@ void p3GxsTunnelService::flush() { if(locked_sendEncryptedTunnelData(it->second.data_item)) { +#ifdef DEBUG_GXS_TUNNEL std::cerr << " sending data item #" << std::hex << it->first << std::dec << std::endl; +#endif it->second.last_sending_attempt = now ; } +#ifdef DEBUG_GXS_TUNNEL else std::cerr << " Cannot send item " << std::hex << it->first << std::dec << std::endl; +#endif } } @@ -182,7 +193,9 @@ void p3GxsTunnelService::flush() { if(it->second.last_contact+20+GXS_TUNNEL_KEEP_ALIVE_TIMEOUT < now && it->second.status == RS_GXS_TUNNEL_STATUS_CAN_TALK) { +#ifdef DEBUG_GXS_TUNNEL std::cerr << "(II) GxsTunnelService:: connexion interrupted with peer." << std::endl; +#endif it->second.status = RS_GXS_TUNNEL_STATUS_TUNNEL_DN ; it->second.virtual_peer_id.clear() ; @@ -192,7 +205,9 @@ void p3GxsTunnelService::flush() if(it->second.direction == RsTurtleGenericTunnelItem::DIRECTION_SERVER) { +#ifdef DEBUG_GXS_TUNNEL std::cerr << "(II) GxsTunnelService:: forcing new tunnel campain." << std::endl; +#endif mTurtle->forceReDiggTunnels( randomHashFromDestinationGxsId(it->second.to_gxs_id) ); } @@ -252,8 +267,10 @@ void p3GxsTunnelService::handleRecvTunnelDataAckItem(const RsGxsTunnelId& id,RsG { RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ +#ifdef DEBUG_GXS_TUNNEL std::cerr << "p3GxsTunnelService::handling RecvTunnelDataAckItem()" << std::endl; std::cerr << " item counter = " << std::hex << item->unique_item_counter << std::dec << std::endl; +#endif // remove it from the queue. @@ -285,10 +302,12 @@ void p3GxsTunnelService::handleRecvTunnelDataItem(const RsGxsTunnelId& tunnel_id // notify the client for the received data +#ifdef DEBUG_GXS_TUNNEL std::cerr << "p3GxsTunnelService::handleRecvTunnelDataItem()" << std::endl; std::cerr << " data size = " << item->data_size << std::endl; std::cerr << " service id = " << std::hex << item->service_id << std::dec << std::endl; std::cerr << " counter id = " << std::hex << item->unique_item_counter << std::dec << std::endl; +#endif RsGxsTunnelClientService *service = NULL ; { @@ -319,7 +338,9 @@ void p3GxsTunnelService::handleRecvStatusItem(const RsGxsTunnelId& tunnel_id, Rs std::vector notifications ; std::set clients ; +#ifdef DEBUG_GXS_TUNNEL std::cerr << "p3GxsTunnelService::handleRecvStatusItem(): tunnel_id=" << tunnel_id << " status=" << cs->status << std::endl; +#endif switch(cs->status) { @@ -347,12 +368,16 @@ void p3GxsTunnelService::handleRecvStatusItem(const RsGxsTunnelId& tunnel_id, Rs break ; case RS_GXS_TUNNEL_FLAG_KEEP_ALIVE: +#ifdef DEBUG_GXS_TUNNEL std::cerr << "GxsTunnelService::handleRecvGxsTunnelStatusItem(): received keep alive packet for inactive tunnel! peerId=" << cs->PeerId() << " tunnel=" << tunnel_id << std::endl; +#endif break ; case RS_GXS_TUNNEL_FLAG_ACK_DISTANT_CONNECTION: { +#ifdef DEBUG_GXS_TUNNEL std::cerr << "Received ACK item from the distant peer!" << std::endl; +#endif // in this case we notify the clients using this tunnel. @@ -367,7 +392,9 @@ void p3GxsTunnelService::handleRecvStatusItem(const RsGxsTunnelId& tunnel_id, Rs // notify all clients +#ifdef DEBUG_GXS_TUNNEL std::cerr << " notifying clients. Prending notifications: " << notifications.size() << std::endl; +#endif if(notifications.size() > 0) { @@ -375,7 +402,9 @@ void p3GxsTunnelService::handleRecvStatusItem(const RsGxsTunnelId& tunnel_id, Rs std::map::iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; +#ifdef DEBUG_GXS_TUNNEL std::cerr << " " << it->second.client_services.size() << " client services for tunnel id " << tunnel_id << std::endl; +#endif for(std::set::const_iterator it2(it->second.client_services.begin());it2!=it->second.client_services.end();++it2) { @@ -386,13 +415,17 @@ void p3GxsTunnelService::handleRecvStatusItem(const RsGxsTunnelId& tunnel_id, Rs } } +#ifdef DEBUG_GXS_TUNNEL std::cerr << " notifying " << clients.size() << " clients." << std::endl; +#endif for(std::set::const_iterator it(clients.begin());it!=clients.end();++it) for(uint32_t i=0;inotifyTunnelStatus(tunnel_id,notifications[i]) ; +#ifdef DEBUG_GXS_TUNNEL std::cerr << " notifying client " << (void*)(*it) << " of status " << notifications[i] << std::endl; +#endif } } @@ -466,7 +499,9 @@ void p3GxsTunnelService::addVirtualPeer(const TurtleFileHash& hash,const TurtleV if(it->second.status == RS_GXS_TUNNEL_STATUS_CAN_TALK) { +#ifdef DEBUG_GXS_TUNNEL std::cerr << " virtual peer is for a distant chat session that is already openned and alive. Giving it up." << std::endl; +#endif return ; } @@ -1209,10 +1244,12 @@ bool p3GxsTunnelService::sendData(const RsGxsTunnelId &tunnel_id, uint32_t servi { // make sure that the tunnel ID is registered. +#ifdef DEBUG_GXS_TUNNEL std::cerr << "p3GxsTunnelService::sendData()" << std::endl; std::cerr << " tunnel id : " << tunnel_id << std::endl; std::cerr << " data size : " << size << std::endl; std::cerr << " service id: " << std::hex << service_id << std::dec << std::endl; +#endif RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ @@ -1232,7 +1269,9 @@ bool p3GxsTunnelService::sendData(const RsGxsTunnelId &tunnel_id, uint32_t servi return false ; } +#ifdef DEBUG_GXS_TUNNEL std::cerr << " verifications fine! Storing in out queue with:" << std::endl; +#endif RsGxsTunnelDataItem *item = new RsGxsTunnelDataItem ; @@ -1249,7 +1288,9 @@ bool p3GxsTunnelService::sendData(const RsGxsTunnelId &tunnel_id, uint32_t servi tdata.data_item = item ; tdata.last_sending_attempt = 0 ; // never sent until now +#ifdef DEBUG_GXS_TUNNEL std::cerr << " counter id : " << std::hex << item->unique_item_counter << std::dec << std::endl; +#endif return true ; } @@ -1268,7 +1309,9 @@ void p3GxsTunnelService::startClientGxsTunnelConnection(const RsGxsId& to_gxs_id if(_gxs_tunnel_contacts.find(tunnel_id) != _gxs_tunnel_contacts.end()) { +#ifdef DEBUG_GXS_TUNNEL std::cerr << "GxsTunnelService:: asking GXS tunnel for a configuration that already exits.Ignoring." << std::endl; +#endif return ; } } @@ -1480,6 +1523,11 @@ void p3GxsTunnelService::debug_dump() for(std::map::const_iterator it=_gxs_tunnel_virtual_peer_ids.begin();it!=_gxs_tunnel_virtual_peer_ids.end();++it) std::cerr << " vpid=" << it->first << " to=" << it->second.gxs_id << " from=" << it->second.own_gxs_id << " tunnel_id=" << it->second.tunnel_id << " status=" << it->second.status << " direction=" << it->second.direction << " hash=" << it->second.hash << std::endl; + + std::cerr << " Pending items: " << std::endl; + std::cerr << " DH : " << pendingDHItems.size() << std::endl; + std::cerr << " Tunnel Management: " << pendingGxsTunnelItems.size() << std::endl; + std::cerr << " Data (client) : " << pendingGxsTunnelDataItems.size() << std::endl; } From 60d948b5095b7758dc35f7c0e38ea722c4b67ec8 Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 30 Nov 2015 21:52:15 -0500 Subject: [PATCH 17/26] added void GUI for authenticated tunnels --- .../src/gui/statistics/TurtleRouterDialog.cpp | 121 ++++++++++++++++++ .../src/gui/statistics/TurtleRouterDialog.h | 27 ++++ .../gui/statistics/TurtleRouterStatistics.cpp | 4 +- 3 files changed, 150 insertions(+), 2 deletions(-) diff --git a/retroshare-gui/src/gui/statistics/TurtleRouterDialog.cpp b/retroshare-gui/src/gui/statistics/TurtleRouterDialog.cpp index 682a20e7c..0982c8f8e 100644 --- a/retroshare-gui/src/gui/statistics/TurtleRouterDialog.cpp +++ b/retroshare-gui/src/gui/statistics/TurtleRouterDialog.cpp @@ -216,3 +216,124 @@ QTreeWidgetItem *TurtleRouterDialog::findParentHashItem(const std::string& hash) else return items.front() ; } +//=======================================================================================================================// + + +GxsTunnelsDialog::GxsTunnelsDialog(QWidget *parent) + : RsAutoUpdatePage(2000,parent) +{ + setupUi(this) ; + + m_bProcessSettings = false; + + float fontHeight = QFontMetricsF(font()).height(); + float fact = fontHeight/14.0; + + maxWidth = 200 ; + maxHeight = 0 ; + + // load settings + processSettings(true); +} + +GxsTunnelsDialog::~GxsTunnelsDialog() +{ + + // save settings + processSettings(false); +} + +void GxsTunnelsDialog::processSettings(bool bLoad) +{ + m_bProcessSettings = true; + + Settings->beginGroup(QString("TurtleRouterStatistics")); + + if (bLoad) { + // load settings + } else { + // save settings + } + + Settings->endGroup(); + + m_bProcessSettings = false; +} + +void GxsTunnelsDialog::updateDisplay() +{ + QPixmap tmppixmap(maxWidth, maxHeight); + tmppixmap.fill(Qt::transparent); + setFixedHeight(maxHeight); + + QPainter painter(&tmppixmap); + painter.initFrom(this); + + // extracts the height of the fonts in pixels. This is used to callibrate the size of the objects to draw. + + float fontHeight = QFontMetricsF(font()).height(); + float fact = fontHeight/14.0; + maxHeight = 500*fact ; + + int cellx = 6*fact ; + int celly = (10+4)*fact ; + + // std::cerr << "Drawing into pixmap of size " << maxWidth << "x" << maxHeight << std::endl; + // draw... + int ox=5*fact,oy=5*fact ; + +// painter.setPen(QColor::fromRgb(70,70,70)) ; +// painter.drawLine(0,oy,maxWidth,oy) ; +// oy += celly ; + + painter.drawText(ox+2*cellx,oy+celly,tr("Authenticated tunnels:")) ; oy += celly ; + + // update the pixmap + // + pixmap = tmppixmap; + maxHeight = oy ; +} + +QString GxsTunnelsDialog::getPeerName(const RsPeerId &peer_id) +{ + static std::map names ; + + std::map::const_iterator it = names.find(peer_id) ; + + if( it != names.end()) + return it->second ; + else + { + RsPeerDetails detail ; + if(!rsPeers->getPeerDetails(peer_id,detail)) + return tr("Unknown Peer"); + + return (names[peer_id] = QString::fromUtf8(detail.name.c_str())) ; + } +} + +QString GxsTunnelsDialog::speedString(float f) +{ + if(f < 1.0f) + return QString("0 B/s") ; + if(f < 1024.0f) + return QString::number((int)f)+" B/s" ; + + return QString::number(f/1024.0,'f',2) + " KB/s"; +} + +void GxsTunnelsDialog::paintEvent(QPaintEvent */*event*/) +{ + QStylePainter(this).drawPixmap(0, 0, pixmap); +} + +void GxsTunnelsDialog::resizeEvent(QResizeEvent *event) +{ + QRect TaskGraphRect = geometry(); + + maxWidth = TaskGraphRect.width(); + maxHeight = TaskGraphRect.height() ; + + QWidget::resizeEvent(event); + update(); +} diff --git a/retroshare-gui/src/gui/statistics/TurtleRouterDialog.h b/retroshare-gui/src/gui/statistics/TurtleRouterDialog.h index 77bb4359e..83c2dceed 100644 --- a/retroshare-gui/src/gui/statistics/TurtleRouterDialog.h +++ b/retroshare-gui/src/gui/statistics/TurtleRouterDialog.h @@ -35,3 +35,30 @@ class TurtleRouterDialog: public RsAutoUpdatePage, public Ui::TurtleRouterDialog QTreeWidgetItem *top_level_t_requests ; } ; + +class GxsTunnelsDialog: public RsAutoUpdatePage, public Ui::TurtleRouterDialogForm +{ + Q_OBJECT + +public: + GxsTunnelsDialog(QWidget *parent = NULL) ; + ~GxsTunnelsDialog(); + + // Cache for peer names. + static QString getPeerName(const RsPeerId &peer_id) ; + +protected: + virtual void paintEvent(QPaintEvent *); + virtual void resizeEvent(QResizeEvent *event); +private: + void processSettings(bool bLoad); + bool m_bProcessSettings; + static QString speedString(float f); + + virtual void updateDisplay() ; + + int maxWidth ; + int maxHeight ; + + QPixmap pixmap; +} ; diff --git a/retroshare-gui/src/gui/statistics/TurtleRouterStatistics.cpp b/retroshare-gui/src/gui/statistics/TurtleRouterStatistics.cpp index 7b432e597..242203388 100644 --- a/retroshare-gui/src/gui/statistics/TurtleRouterStatistics.cpp +++ b/retroshare-gui/src/gui/statistics/TurtleRouterStatistics.cpp @@ -195,8 +195,8 @@ TurtleRouterStatistics::TurtleRouterStatistics(QWidget *parent) _tunnel_statistics_F->setFrameStyle(QFrame::NoFrame); _tunnel_statistics_F->setFocusPolicy(Qt::NoFocus); - routertabWidget->addTab(new TurtleRouterDialog(),QString(tr("Tunnel Requests"))); - + routertabWidget->addTab(new TurtleRouterDialog(),QString(tr("Tunnels"))); + routertabWidget->addTab(new GxsTunnelsDialog(),QString(tr("Authenticated pipes"))); float fontHeight = QFontMetricsF(font()).height(); float fact = fontHeight/14.0; From 81b196d38d488ca2e3599faa115f9cc09fde6477 Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 1 Dec 2015 23:40:35 -0500 Subject: [PATCH 18/26] added GUI to display authenticated tunnel info. Added counting of data sent/recvd. --- libretroshare/src/gxstunnel/p3gxstunnel.cc | 71 +++++++++++-------- libretroshare/src/gxstunnel/p3gxstunnel.h | 7 +- libretroshare/src/retroshare/rsgxstunnel.h | 7 +- .../src/gui/statistics/TurtleRouterDialog.cpp | 61 ++++++++++++---- .../src/gui/statistics/TurtleRouterDialog.h | 3 +- 5 files changed, 100 insertions(+), 49 deletions(-) diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.cc b/libretroshare/src/gxstunnel/p3gxstunnel.cc index 36442d978..0d3f69b7e 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.cc +++ b/libretroshare/src/gxstunnel/p3gxstunnel.cc @@ -140,9 +140,11 @@ void p3GxsTunnelService::flush() { RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - while(!pendingDHItems.empty()) - if(locked_sendClearTunnelData(pendingDHItems.front()) ) - pendingDHItems.pop_front() ; + for(std::list::iterator it=pendingDHItems.begin();it!=pendingDHItems.end();) + if(locked_sendClearTunnelData(*it) ) + it = pendingDHItems.erase(it) ; + else + ++it ; } // Flush items that could not be sent, probably because of a Mutex protected zone. @@ -150,13 +152,16 @@ void p3GxsTunnelService::flush() { RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - while(!pendingGxsTunnelItems.empty()) - if(locked_sendEncryptedTunnelData(pendingGxsTunnelItems.front())) - pendingGxsTunnelItems.pop_front() ; -#ifdef DEBUG_GXS_TUNNEL + for(std::list::iterator it=pendingGxsTunnelItems.begin();it!=pendingGxsTunnelItems.end();) + if(locked_sendEncryptedTunnelData(*it) ) + it = pendingGxsTunnelItems.erase(it) ; else - std::cerr << "Cannot send encrypted data item to tunnel " << pendingGxsTunnelItems.front()->PeerId() << std::endl; + { + ++it ; +#ifdef DEBUG_GXS_TUNNEL + std::cerr << "Cannot send encrypted data item to tunnel " << (*it)->PeerId() << std::endl; #endif + } } // Look at pending data item, and re-send them if necessary. @@ -772,6 +777,8 @@ bool p3GxsTunnelService::handleEncryptedData(const uint8_t *data_bytes,uint32_t return true; } + it2->second.total_received += decrypted_size ; + // DH key items are sent even before we know who we speak to, so the virtual peer id is used in this // case only. @@ -1158,6 +1165,8 @@ bool p3GxsTunnelService::locked_sendEncryptedTunnelData(RsGxsTunnelItem *item) return false; } + it->second.total_sent += rssize ; // counts the size of clear data that is sent + memcpy(aes_key,it->second.aes_key,GXS_TUNNEL_AES_KEY_SIZE) ; RsPeerId virtual_peer_id = it->second.virtual_peer_id ; @@ -1387,9 +1396,8 @@ bool p3GxsTunnelService::getTunnelInfo(const RsGxsTunnelId& tunnel_id,GxsTunnelI info.destination_gxs_id = it->second.to_gxs_id; info.source_gxs_id = it->second.own_gxs_id; info.tunnel_status = it->second.status; -#warning data missing here - info.total_size_sent = 0; - info.total_size_received= 0; + info.total_size_sent = it->second.total_sent; + info.total_size_received= it->second.total_received; // Data packets @@ -1400,24 +1408,6 @@ bool p3GxsTunnelService::getTunnelInfo(const RsGxsTunnelId& tunnel_id,GxsTunnelI return true ; } -bool p3GxsTunnelService::getTunnelStatus(const RsGxsTunnelId& tunnel_id,uint32_t& status) -{ - RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - - std::map::const_iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; - - if(it != _gxs_tunnel_contacts.end()) - { - status = it->second.status ; - - return true ; - } - - status = RS_GXS_TUNNEL_STATUS_UNKNOWN ; - - return false ; -} - bool p3GxsTunnelService::closeExistingTunnel(const RsGxsTunnelId& tunnel_id, uint32_t service_id) { // two cases: @@ -1499,7 +1489,28 @@ bool p3GxsTunnelService::closeExistingTunnel(const RsGxsTunnelId& tunnel_id, uin // GxsTunnelService::removeVirtualPeerId() will be called by the turtle service. } - return true ; + return true ; +} + +bool p3GxsTunnelService::getTunnelsInfo(std::vector &infos) +{ + RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + + for(std::map::const_iterator it(_gxs_tunnel_contacts.begin());it!=_gxs_tunnel_contacts.end();++it) + { + GxsTunnelInfo ti ; + + ti.tunnel_id = it->first ; + ti.destination_gxs_id = it->second.to_gxs_id ; + ti.source_gxs_id = it->second.own_gxs_id ; + ti.tunnel_status = it->second.status ; + ti.total_size_sent = it->second.total_sent ; + ti.total_size_received = it->second.total_received ; + + infos.push_back(ti) ; + } + + return true ; } void p3GxsTunnelService::debug_dump() diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.h b/libretroshare/src/gxstunnel/p3gxstunnel.h index 3163de06f..488e3b914 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.h +++ b/libretroshare/src/gxstunnel/p3gxstunnel.h @@ -138,7 +138,7 @@ public: virtual bool requestSecuredTunnel(const RsGxsId& to_id,const RsGxsId& from_id,RsGxsTunnelId& tunnel_id,uint32_t service_id,uint32_t& error_code) ; virtual bool closeExistingTunnel(const RsGxsTunnelId &tunnel_id,uint32_t service_id) ; - virtual bool getTunnelStatus(const RsGxsTunnelId& tunnel_id,uint32_t &status); + virtual bool getTunnelsInfo(std::vector& infos); virtual bool getTunnelInfo(const RsGxsTunnelId& tunnel_id,GxsTunnelInfo& info); virtual bool sendData(const RsGxsTunnelId& tunnel_id,uint32_t service_id,const uint8_t *data,uint32_t size) ; @@ -159,6 +159,9 @@ private: GxsTunnelPeerInfo() : last_contact(0), last_keep_alive_sent(0), status(0), direction(0) { memset(aes_key, 0, GXS_TUNNEL_AES_KEY_SIZE); + + total_sent = 0 ; + total_received = 0 ; } time_t last_contact ; // used to keep track of working connexion @@ -173,6 +176,8 @@ private: RsTurtleGenericTunnelItem::Direction direction ; // specifiec wether we are client(managing the tunnel) or server. TurtleFileHash hash ; // hash that is last used. This is necessary for handling tunnel establishment std::set client_services ;// services that used this tunnel + uint32_t total_sent ; + uint32_t total_received ; }; class GxsTunnelDHInfo diff --git a/libretroshare/src/retroshare/rsgxstunnel.h b/libretroshare/src/retroshare/rsgxstunnel.h index 6263c30e5..671441920 100644 --- a/libretroshare/src/retroshare/rsgxstunnel.h +++ b/libretroshare/src/retroshare/rsgxstunnel.h @@ -68,8 +68,9 @@ public: class GxsTunnelInfo { public: - // Tunnel information - + // Tunnel information + + RsGxsTunnelId tunnel_id ; RsGxsId destination_gxs_id ; // GXS Id we're talking to RsGxsId source_gxs_id ; // GXS Id we're using to talk uint32_t tunnel_status ; // active, requested, DH pending, etc. @@ -89,7 +90,7 @@ public: // Debugging info // //===================================================// - //virtual bool getGxsTunnelsInfo(std::vector& infos) =0; + virtual bool getTunnelsInfo(std::vector& infos) =0; virtual bool getTunnelInfo(const RsGxsTunnelId& tunnel_id,GxsTunnelInfo& info) =0; // retrieve the routing probabilities diff --git a/retroshare-gui/src/gui/statistics/TurtleRouterDialog.cpp b/retroshare-gui/src/gui/statistics/TurtleRouterDialog.cpp index 0982c8f8e..a216e2102 100644 --- a/retroshare-gui/src/gui/statistics/TurtleRouterDialog.cpp +++ b/retroshare-gui/src/gui/statistics/TurtleRouterDialog.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "TurtleRouterDialog.h" #include #include @@ -222,7 +223,7 @@ QTreeWidgetItem *TurtleRouterDialog::findParentHashItem(const std::string& hash) GxsTunnelsDialog::GxsTunnelsDialog(QWidget *parent) : RsAutoUpdatePage(2000,parent) { - setupUi(this) ; +// setupUi(this) ; m_bProcessSettings = false; @@ -230,7 +231,7 @@ GxsTunnelsDialog::GxsTunnelsDialog(QWidget *parent) float fact = fontHeight/14.0; maxWidth = 200 ; - maxHeight = 0 ; + maxHeight = 200 ; // load settings processSettings(true); @@ -262,36 +263,68 @@ void GxsTunnelsDialog::processSettings(bool bLoad) void GxsTunnelsDialog::updateDisplay() { + // Request info about ongoing tunnels + + std::vector tunnel_infos ; + + rsGxsTunnel->getTunnelsInfo(tunnel_infos) ; + + // // Tunnel information + // + // GxsTunnelId tunnel_id ; // GXS Id we're talking to + // RsGxsId destination_gxs_id ; // GXS Id we're talking to + // RsGxsId source_gxs_id ; // GXS Id we're using to talk + // uint32_t tunnel_status ; // active, requested, DH pending, etc. + // uint32_t total_size_sent ; // total bytes sent through that tunnel since openned (including management). + // uint32_t total_size_received ; // total bytes received through that tunnel since openned (including management). + + // // Data packets + + // uint32_t pending_data_packets; // number of packets not acknowledged by other side, still on their way. Should be 0 unless something bad happens. + // uint32_t total_data_packets_sent ; // total number of data packets sent (does not include tunnel management) + // uint32_t total_data_packets_received ; // total number of data packets received (does not include tunnel management) + + // now draw the shit QPixmap tmppixmap(maxWidth, maxHeight); tmppixmap.fill(Qt::transparent); - setFixedHeight(maxHeight); + //setFixedHeight(maxHeight); QPainter painter(&tmppixmap); painter.initFrom(this); - // extracts the height of the fonts in pixels. This is used to callibrate the size of the objects to draw. + // extracts the height of the fonts in pixels. This is used to calibrate the size of the objects to draw. float fontHeight = QFontMetricsF(font()).height(); float fact = fontHeight/14.0; - maxHeight = 500*fact ; + //maxHeight = 500*fact ; int cellx = 6*fact ; int celly = (10+4)*fact ; + int ox=5*fact,oy=5*fact ; - // std::cerr << "Drawing into pixmap of size " << maxWidth << "x" << maxHeight << std::endl; - // draw... - int ox=5*fact,oy=5*fact ; - -// painter.setPen(QColor::fromRgb(70,70,70)) ; -// painter.drawLine(0,oy,maxWidth,oy) ; -// oy += celly ; - + painter.setPen(QColor::fromRgb(0,0,0)) ; painter.drawText(ox+2*cellx,oy+celly,tr("Authenticated tunnels:")) ; oy += celly ; + + for(uint32_t i=0;i #include #include "ui_TurtleRouterDialog.h" +#include "ui_TurtleRouterStatistics.h" #include "RsAutoUpdatePage.h" @@ -36,7 +37,7 @@ class TurtleRouterDialog: public RsAutoUpdatePage, public Ui::TurtleRouterDialog } ; -class GxsTunnelsDialog: public RsAutoUpdatePage, public Ui::TurtleRouterDialogForm +class GxsTunnelsDialog: public RsAutoUpdatePage { Q_OBJECT From 9f561993eef7feea42e5236a4610475953d617dc Mon Sep 17 00:00:00 2001 From: realityfabric Date: Wed, 2 Dec 2015 06:18:17 -0800 Subject: [PATCH 19/26] fixed spelling errors in several files --- build_scripts/Debian+Ubuntu/changelog | 4 ++-- libretroshare/src/chat/distributedchat.cc | 2 +- retroshare-gui/src/changelog.txt | 6 +++--- retroshare-gui/src/gui/MainWindow.cpp | 2 +- retroshare-gui/src/gui/RemoteDirModel.cpp | 2 +- retroshare-gui/src/gui/common/GroupSelectionBox.cpp | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/build_scripts/Debian+Ubuntu/changelog b/build_scripts/Debian+Ubuntu/changelog index 70bbeb0e0..a84fe88b6 100644 --- a/build_scripts/Debian+Ubuntu/changelog +++ b/build_scripts/Debian+Ubuntu/changelog @@ -1851,7 +1851,7 @@ retroshare (0.5.4-0.6685~precise) precise; urgency=low * Bug fixes - - Added missing location from cert when addign new friend + - Added missing location from cert when adding new friend - Added missing IndicateConfigChanged to p3PeerMgrIMPL::setDynDNS - Fixed crash when closing the main window without the setting "Minimize to Tray Icon" - Renamed the setting "Do not Minimize to Tray Icon" to "Minimize to Tray @@ -2925,7 +2925,7 @@ retroshare (0.5.3-0.4953~natty) natty; urgency=low - Fixed Download toaster (utf8 in file name, use QDesktopServices vs RsUrlHandler for collections, fixed crash after opening a collection) (Patch from AsamK). - fixed utf8 chars in certificate links (Patch from AsamK) - - removed cache adding strategy to DL queue that was O(n^2). Now addign cache at the end of the queue + - removed cache adding strategy to DL queue that was O(n^2). Now adding cache at the end of the queue - Fixed bug when the user clicks on a link without http:// in a QTextBrowser. This link was oppened directly in RetroShare. - Attempted fix for maintaining External Port in Manual Forwarded Mode. diff --git a/libretroshare/src/chat/distributedchat.cc b/libretroshare/src/chat/distributedchat.cc index 72a3f2a93..d0fdaab0b 100644 --- a/libretroshare/src/chat/distributedchat.cc +++ b/libretroshare/src/chat/distributedchat.cc @@ -1288,7 +1288,7 @@ void DistributedChatService::handleRecvLobbyInvite(RsChatLobbyInviteItem *item) else std::cerr << " : Match!" << std::endl; - std::cerr << " Addign new friend " << item->PeerId() << " to lobby." << std::endl; + std::cerr << " Adding new friend " << item->PeerId() << " to lobby." << std::endl; #endif it->second.participating_friends.insert(item->PeerId()) ; diff --git a/retroshare-gui/src/changelog.txt b/retroshare-gui/src/changelog.txt index c535d3a42..3da31f03c 100644 --- a/retroshare-gui/src/changelog.txt +++ b/retroshare-gui/src/changelog.txt @@ -364,7 +364,7 @@ Changes for 0.5.5a * Bug fixes - Fixed proper display of crypto params for UDP connections - - Added missing location from cert when addign new friend + - Added missing location from cert when adding new friend - Added missing IndicateConfigChanged to p3PeerMgrIMPL::setDynDNS - Fixed crash when closing the main window without the setting "Minimize to Tray Icon" - Renamed the setting "Do not Minimize to Tray Icon" to "Minimize to Tray @@ -1189,7 +1189,7 @@ Changes for v0.5.3b - Added BSD specific changes - data directory and #including - improved plugin management to allow services to be used, and config pages to be added - Improvement to plugin system: - - made config page system more automatic, to allow addign config pages from plugins + - made config page system more automatic, to allow adding config pages from plugins - added (disabled) checkbox and function to allow all plugins for development - added config page methods to RsPlugin class - Mark local existing files in SearchDialog with red text color. @@ -1202,7 +1202,7 @@ Changes for v0.5.3b - Added Cache system for GPG Certificates. - This should reduce gpg calls by 90+%. - Added translation for "[ ... Missing Message ... ]". - - removed cache adding strategy to DL queue that was O(n^2). Now addign cache at the end of the queue + - removed cache adding strategy to DL queue that was O(n^2). Now adding cache at the end of the queue - The channel message (in channels) is set to read when the user clicks on the show more button. - The forum/channel news feed is removed when the user reads the message in forums/channels. - The standard font is now used for new chat lobbies. diff --git a/retroshare-gui/src/gui/MainWindow.cpp b/retroshare-gui/src/gui/MainWindow.cpp index e3b975843..3efd0c23d 100644 --- a/retroshare-gui/src/gui/MainWindow.cpp +++ b/retroshare-gui/src/gui/MainWindow.cpp @@ -401,7 +401,7 @@ void MainWindow::initStackedPage() else icon = QIcon(":images/extension_48.png") ; - std::cerr << " Addign widget page for plugin " << rsPlugins->plugin(i)->getPluginName() << std::endl; + std::cerr << " Adding widget page for plugin " << rsPlugins->plugin(i)->getPluginName() << std::endl; pluginPage->setIconPixmap(icon); pluginPage->setPageName(QString::fromUtf8(rsPlugins->plugin(i)->getPluginName().c_str())); addPage(pluginPage, grp, ¬ify); diff --git a/retroshare-gui/src/gui/RemoteDirModel.cpp b/retroshare-gui/src/gui/RemoteDirModel.cpp index 6c64a7b89..fddb96ee3 100644 --- a/retroshare-gui/src/gui/RemoteDirModel.cpp +++ b/retroshare-gui/src/gui/RemoteDirModel.cpp @@ -1341,7 +1341,7 @@ void FlatStyle_RDM::updateRefs() if(details->type == DIR_TYPE_FILE) // only push files, not directories nor persons. _ref_entries.push_back(std::pair(ref,computeDirectoryPath(*details))); #ifdef RDM_DEBUG - std::cerr << "FlatStyle_RDM::postMods(): addign ref " << ref << std::endl; + std::cerr << "FlatStyle_RDM::postMods(): adding ref " << ref << std::endl; #endif for(std::list::const_iterator it = details->children.begin(); it != details->children.end(); ++it) _ref_stack.push_back(it->ref) ; diff --git a/retroshare-gui/src/gui/common/GroupSelectionBox.cpp b/retroshare-gui/src/gui/common/GroupSelectionBox.cpp index 55317115d..613459019 100644 --- a/retroshare-gui/src/gui/common/GroupSelectionBox.cpp +++ b/retroshare-gui/src/gui/common/GroupSelectionBox.cpp @@ -46,7 +46,7 @@ void GroupSelectionBox::selectedGroupIds(std::list &groupIds) const QListWidgetItem *listItem = item(i); if (listItem->checkState() == Qt::Checked) { groupIds.push_back(item(i)->data(ROLE_ID).toString().toStdString()); - std::cerr << "Addign selected item " << groupIds.back() << std::endl; + std::cerr << "Adding selected item " << groupIds.back() << std::endl; } } } @@ -74,7 +74,7 @@ void GroupSelectionBox::selectedGroupNames(QList &groupNames) const QListWidgetItem *listItem = item(i); if (listItem->checkState() == Qt::Checked) { groupNames.push_back(item(i)->text()); - std::cerr << "Addign selected item " << groupNames.back().toUtf8().constData() << std::endl; + std::cerr << "Adding selected item " << groupNames.back().toUtf8().constData() << std::endl; } } } From b198f1a007e4cbe4894b5e84bb4fc2fa98a347b5 Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 3 Dec 2015 00:34:13 -0500 Subject: [PATCH 20/26] fixed some cleaning of remotely closed tunnels in GxsTunnelService --- libretroshare/src/gxstunnel/p3gxstunnel.cc | 197 ++++++++++-------- .../src/gui/chat/PopupDistantChatDialog.cpp | 2 +- 2 files changed, 106 insertions(+), 93 deletions(-) diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.cc b/libretroshare/src/gxstunnel/p3gxstunnel.cc index 0d3f69b7e..b837ba469 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.cc +++ b/libretroshare/src/gxstunnel/p3gxstunnel.cc @@ -194,8 +194,19 @@ void p3GxsTunnelService::flush() time_t now = time(NULL) ; - for(std::map::iterator it(_gxs_tunnel_contacts.begin());it!=_gxs_tunnel_contacts.end();++it) + for(std::map::iterator it(_gxs_tunnel_contacts.begin());it!=_gxs_tunnel_contacts.end();) { + // Remove any tunnel that was remotely closed, since we cannot use it anymore. + + if(it->second.status == RS_GXS_TUNNEL_STATUS_REMOTELY_CLOSED && it->second.last_contact + 20 < now) + { + std::map::iterator tmp = it ; + ++tmp ; + _gxs_tunnel_contacts.erase(it) ; + it=tmp ; + continue ; + } + if(it->second.last_contact+20+GXS_TUNNEL_KEEP_ALIVE_TIMEOUT < now && it->second.status == RS_GXS_TUNNEL_STATUS_CAN_TALK) { #ifdef DEBUG_GXS_TUNNEL @@ -233,6 +244,7 @@ void p3GxsTunnelService::flush() std::cerr << "(II) GxsTunnelService:: Sending keep alive packet to gxs id " << it->first << std::endl; #endif } + ++it ; } } @@ -340,98 +352,98 @@ void p3GxsTunnelService::handleRecvTunnelDataItem(const RsGxsTunnelId& tunnel_id void p3GxsTunnelService::handleRecvStatusItem(const RsGxsTunnelId& tunnel_id, RsGxsTunnelStatusItem *cs) { - std::vector notifications ; - std::set clients ; + std::vector notifications ; + std::set clients ; #ifdef DEBUG_GXS_TUNNEL - std::cerr << "p3GxsTunnelService::handleRecvStatusItem(): tunnel_id=" << tunnel_id << " status=" << cs->status << std::endl; + std::cerr << "p3GxsTunnelService::handleRecvStatusItem(): tunnel_id=" << tunnel_id << " status=" << cs->status << std::endl; #endif - switch(cs->status) - { - case RS_GXS_TUNNEL_FLAG_CLOSING_DISTANT_CONNECTION: - { - RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + switch(cs->status) + { + case RS_GXS_TUNNEL_FLAG_CLOSING_DISTANT_CONNECTION: + { + RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - std::map::iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; + std::map::iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; - if(it == _gxs_tunnel_contacts.end()) - { - std::cerr << "(EE) Cannot mark tunnel connection as closed. No connection openned for tunnel id " << tunnel_id << ". Unexpected situation." << std::endl; - return ; - } + if(it == _gxs_tunnel_contacts.end()) + { + std::cerr << "(EE) Cannot mark tunnel connection as closed. No connection openned for tunnel id " << tunnel_id << ". Unexpected situation." << std::endl; + return ; + } - if(it->second.direction == RsTurtleGenericDataItem::DIRECTION_CLIENT) - { + if(it->second.direction == RsTurtleGenericDataItem::DIRECTION_CLIENT) + { #ifdef DEBUG_GXS_TUNNEL - std::cerr << " This is server side. Marking distant chat as remotely closed for tunnel id " << tunnel_id << std::endl; + std::cerr << " This is server side. Marking distant chat as remotely closed for tunnel id " << tunnel_id << std::endl; #endif - it->second.status = RS_GXS_TUNNEL_STATUS_REMOTELY_CLOSED ; - notifications.push_back(RS_GXS_TUNNEL_STATUS_REMOTELY_CLOSED) ; - } - } // nothing more to do, because the decryption routing will update the last_contact time when decrypting. - break ; + it->second.status = RS_GXS_TUNNEL_STATUS_REMOTELY_CLOSED ; + notifications.push_back(RS_GXS_TUNNEL_STATUS_REMOTELY_CLOSED) ; + } + } // nothing more to do, because the decryption routing will update the last_contact time when decrypting. + break ; - case RS_GXS_TUNNEL_FLAG_KEEP_ALIVE: + case RS_GXS_TUNNEL_FLAG_KEEP_ALIVE: #ifdef DEBUG_GXS_TUNNEL - std::cerr << "GxsTunnelService::handleRecvGxsTunnelStatusItem(): received keep alive packet for inactive tunnel! peerId=" << cs->PeerId() << " tunnel=" << tunnel_id << std::endl; + std::cerr << "GxsTunnelService::handleRecvGxsTunnelStatusItem(): received keep alive packet for inactive tunnel! peerId=" << cs->PeerId() << " tunnel=" << tunnel_id << std::endl; #endif - break ; + break ; - case RS_GXS_TUNNEL_FLAG_ACK_DISTANT_CONNECTION: - { + case RS_GXS_TUNNEL_FLAG_ACK_DISTANT_CONNECTION: + { #ifdef DEBUG_GXS_TUNNEL - std::cerr << "Received ACK item from the distant peer!" << std::endl; + std::cerr << "Received ACK item from the distant peer!" << std::endl; #endif - // in this case we notify the clients using this tunnel. + // in this case we notify the clients using this tunnel. - notifications.push_back(RS_GXS_TUNNEL_STATUS_CAN_TALK) ; - } - break ; + notifications.push_back(RS_GXS_TUNNEL_STATUS_CAN_TALK) ; + } + break ; - default: - std::cerr << "(EE) unhandled tunnel status " << std::hex << cs->status << std::dec << std::endl; - break ; - } + default: + std::cerr << "(EE) unhandled tunnel status " << std::hex << cs->status << std::dec << std::endl; + break ; + } - // notify all clients + // notify all clients #ifdef DEBUG_GXS_TUNNEL - std::cerr << " notifying clients. Prending notifications: " << notifications.size() << std::endl; + std::cerr << " notifying clients. Prending notifications: " << notifications.size() << std::endl; #endif - - if(notifications.size() > 0) - { - RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - std::map::iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; + if(notifications.size() > 0) + { + RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + + std::map::iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; #ifdef DEBUG_GXS_TUNNEL - std::cerr << " " << it->second.client_services.size() << " client services for tunnel id " << tunnel_id << std::endl; + std::cerr << " " << it->second.client_services.size() << " client services for tunnel id " << tunnel_id << std::endl; #endif - - for(std::set::const_iterator it2(it->second.client_services.begin());it2!=it->second.client_services.end();++it2) - { - std::map::const_iterator it3=mRegisteredServices.find(*it2) ; - if(it3 != mRegisteredServices.end()) - clients.insert(it3->second) ; - } - } + for(std::set::const_iterator it2(it->second.client_services.begin());it2!=it->second.client_services.end();++it2) + { + std::map::const_iterator it3=mRegisteredServices.find(*it2) ; + + if(it3 != mRegisteredServices.end()) + clients.insert(it3->second) ; + } + } #ifdef DEBUG_GXS_TUNNEL - std::cerr << " notifying " << clients.size() << " clients." << std::endl; + std::cerr << " notifying " << clients.size() << " clients." << std::endl; #endif - - for(std::set::const_iterator it(clients.begin());it!=clients.end();++it) - for(uint32_t i=0;inotifyTunnelStatus(tunnel_id,notifications[i]) ; + + for(std::set::const_iterator it(clients.begin());it!=clients.end();++it) + for(uint32_t i=0;inotifyTunnelStatus(tunnel_id,notifications[i]) ; #ifdef DEBUG_GXS_TUNNEL - std::cerr << " notifying client " << (void*)(*it) << " of status " << notifications[i] << std::endl; + std::cerr << " notifying client " << (void*)(*it) << " of status " << notifications[i] << std::endl; #endif - } + } } bool p3GxsTunnelService::handleTunnelRequest(const RsFileHash& hash,const RsPeerId& /*peer_id*/) @@ -1417,7 +1429,8 @@ bool p3GxsTunnelService::closeExistingTunnel(const RsGxsTunnelId& tunnel_id, uin TurtleFileHash hash ; TurtleVirtualPeerId vpid ; - bool close_tunnel = false ; + bool close_tunnel = false ; + int direction ; { RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ std::map::iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; @@ -1432,49 +1445,49 @@ bool p3GxsTunnelService::closeExistingTunnel(const RsGxsTunnelId& tunnel_id, uin } vpid = it->second.virtual_peer_id ; - if(it->second.direction == RsTurtleGenericTunnelItem::DIRECTION_CLIENT) // nothing more to do for server side. - return true ; - std::map::const_iterator it2 = _gxs_tunnel_virtual_peer_ids.find(vpid) ; if(it2 != _gxs_tunnel_virtual_peer_ids.end()) hash = it2->second.hash ; - - // check how many clients are used. If empty, close the tunnel - - std::set::iterator it3 = it->second.client_services.find(service_id) ; - - if(it3 == it->second.client_services.end()) - { - std::cerr << "(EE) service id not currently using that tunnel. This is an error." << std::endl; - return false; - } - - it->second.client_services.erase(it3) ; - - if(it->second.client_services.empty()) - close_tunnel = true ; + + // check how many clients are used. If empty, close the tunnel + + std::set::iterator it3 = it->second.client_services.find(service_id) ; + + if(it3 == it->second.client_services.end()) + { + std::cerr << "(EE) service id not currently using that tunnel. This is an error." << std::endl; + return false; + } + + it->second.client_services.erase(it3) ; + direction = it->second.direction ; + + if(it->second.client_services.empty()) + close_tunnel = true ; } - if(!close_tunnel) - return true ; - - // send a status item saying that we're closing the connection + if(close_tunnel && direction == RsTurtleGenericTunnelItem::DIRECTION_SERVER) // nothing more to do for server side. + { + // send a status item saying that we're closing the connection #ifdef DEBUG_GXS_TUNNEL - std::cerr << " Sending a ACK to close the tunnel since we're managing it and it's not used by any service. tunnel id=." << tunnel_id << std::endl; + std::cerr << " Sending a ACK to close the tunnel since we're managing it and it's not used by any service. tunnel id=." << tunnel_id << std::endl; #endif - RsGxsTunnelStatusItem *cs = new RsGxsTunnelStatusItem ; + RsGxsTunnelStatusItem *cs = new RsGxsTunnelStatusItem ; - cs->status = RS_GXS_TUNNEL_FLAG_CLOSING_DISTANT_CONNECTION; - cs->PeerId(RsPeerId(tunnel_id)) ; + cs->status = RS_GXS_TUNNEL_FLAG_CLOSING_DISTANT_CONNECTION; + cs->PeerId(RsPeerId(tunnel_id)) ; - locked_sendEncryptedTunnelData(cs) ; // that needs to be done off-mutex and before we close the tunnel also ignoring failure. + locked_sendEncryptedTunnelData(cs) ; // that needs to be done off-mutex and before we close the tunnel also ignoring failure. #ifdef DEBUG_GXS_TUNNEL - std::cerr << " This is client side. Stopping tunnel manageement for tunnel_id " << tunnel_id << std::endl; + std::cerr << " This is client side. Stopping tunnel manageement for tunnel_id " << tunnel_id << std::endl; #endif - mTurtle->stopMonitoringTunnels( hash ) ; // still valid if the hash is null + mTurtle->stopMonitoringTunnels( hash ) ; // still valid if the hash is null + } + + if(close_tunnel) { RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ std::map::iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; @@ -1489,7 +1502,7 @@ bool p3GxsTunnelService::closeExistingTunnel(const RsGxsTunnelId& tunnel_id, uin // GxsTunnelService::removeVirtualPeerId() will be called by the turtle service. } - return true ; + return true ; } bool p3GxsTunnelService::getTunnelsInfo(std::vector &infos) diff --git a/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp b/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp index 0aa3c0657..f8be00f33 100644 --- a/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp +++ b/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp @@ -104,7 +104,7 @@ void PopupDistantChatDialog::updateDisplay() { case RS_DISTANT_CHAT_STATUS_UNKNOWN: //std::cerr << "Unknown hash. Error!" << std::endl; _status_label->setPixmap(QPixmap(IMAGE_GRY_LED)) ; - msg = tr("Hash Error. No tunnel."); + msg = tr("Chat remotely closed. Please close this window."); _status_label->setToolTip(msg) ; getChatWidget()->updateStatusString("%1", msg, true); getChatWidget()->blockSending(tr("Can't send message, because there is no tunnel.")); From 318be3a2ad2e9f0f707ccb54f09fbdeff84748c1 Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 4 Dec 2015 00:06:14 -0500 Subject: [PATCH 21/26] fixed a few bugs in distant chat: disabled history (for now), improved tunnel handling --- libretroshare/src/chat/p3chatservice.cc | 15 +- libretroshare/src/gxstunnel/p3gxstunnel.cc | 241 +++++++++--------- libretroshare/src/gxstunnel/p3gxstunnel.h | 37 ++- .../gui/statistics/TurtleRouterStatistics.cpp | 4 +- 4 files changed, 157 insertions(+), 140 deletions(-) diff --git a/libretroshare/src/chat/p3chatservice.cc b/libretroshare/src/chat/p3chatservice.cc index e6b0215c1..9aa02b0e0 100644 --- a/libretroshare/src/chat/p3chatservice.cc +++ b/libretroshare/src/chat/p3chatservice.cc @@ -381,7 +381,12 @@ bool p3ChatService::sendChat(ChatId destination, std::string msg) #endif RsServer::notify()->notifyChatMessage(message); - mHistoryMgr->addMessage(message); + + // cyril: history is temporarily diabled for distant chat, since we need to store the full tunnel ID, but then + // at loading time, the ID is not known so that chat window shows 00000000 as a peer. + + if(!message.chat_id.isDistantChatId()) + mHistoryMgr->addMessage(message); checkSizeAndSendMessage(ci); @@ -752,7 +757,13 @@ bool p3ChatService::handleRecvChatMsgItem(RsChatMsgItem *ci) cm.incoming = true; cm.online = true; RsServer::notify()->notifyChatMessage(cm); - mHistoryMgr->addMessage(cm); + + // cyril: history is temporarily diabled for distant chat, since we need to store the full tunnel ID, but then + // at loading time, the ID is not known so that chat window shows 00000000 as a peer. + + if(!cm.chat_id.isDistantChatId()) + mHistoryMgr->addMessage(cm); + return true ; } diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.cc b/libretroshare/src/gxstunnel/p3gxstunnel.cc index b837ba469..7c571e29e 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.cc +++ b/libretroshare/src/gxstunnel/p3gxstunnel.cc @@ -45,7 +45,7 @@ #include "p3gxstunnel.h" -#define DEBUG_GXS_TUNNEL +//#define DEBUG_GXS_TUNNEL static const uint32_t GXS_TUNNEL_KEEP_ALIVE_TIMEOUT = 6 ; // send keep alive packet so as to avoid tunnel breaks. @@ -352,98 +352,109 @@ void p3GxsTunnelService::handleRecvTunnelDataItem(const RsGxsTunnelId& tunnel_id void p3GxsTunnelService::handleRecvStatusItem(const RsGxsTunnelId& tunnel_id, RsGxsTunnelStatusItem *cs) { - std::vector notifications ; - std::set clients ; + std::vector notifications ; + std::set clients ; #ifdef DEBUG_GXS_TUNNEL - std::cerr << "p3GxsTunnelService::handleRecvStatusItem(): tunnel_id=" << tunnel_id << " status=" << cs->status << std::endl; + std::cerr << "p3GxsTunnelService::handleRecvStatusItem(): tunnel_id=" << tunnel_id << " status=" << cs->status << std::endl; #endif - switch(cs->status) - { - case RS_GXS_TUNNEL_FLAG_CLOSING_DISTANT_CONNECTION: - { - RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + switch(cs->status) + { + case RS_GXS_TUNNEL_FLAG_CLOSING_DISTANT_CONNECTION: + { + RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - std::map::iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; + std::map::iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; - if(it == _gxs_tunnel_contacts.end()) - { - std::cerr << "(EE) Cannot mark tunnel connection as closed. No connection openned for tunnel id " << tunnel_id << ". Unexpected situation." << std::endl; - return ; - } + if(it == _gxs_tunnel_contacts.end()) + { + std::cerr << "(EE) Cannot mark tunnel connection as closed. No connection openned for tunnel id " << tunnel_id << ". Unexpected situation." << std::endl; + return ; + } - if(it->second.direction == RsTurtleGenericDataItem::DIRECTION_CLIENT) - { #ifdef DEBUG_GXS_TUNNEL - std::cerr << " This is server side. Marking distant chat as remotely closed for tunnel id " << tunnel_id << std::endl; + std::cerr << " Marking distant chat as remotely closed for tunnel id " << tunnel_id << std::endl; #endif - it->second.status = RS_GXS_TUNNEL_STATUS_REMOTELY_CLOSED ; - notifications.push_back(RS_GXS_TUNNEL_STATUS_REMOTELY_CLOSED) ; - } - } // nothing more to do, because the decryption routing will update the last_contact time when decrypting. - break ; + if(it->second.direction == RsTurtleGenericDataItem::DIRECTION_CLIENT) + { + it->second.status = RS_GXS_TUNNEL_STATUS_REMOTELY_CLOSED ; +#ifdef DEBUG_GXS_TUNNEL + std::cerr << " This is server side. The tunnel cannot be re-openned, so we give it up." << std::endl; +#endif + } + else + { + it->second.status = RS_GXS_TUNNEL_STATUS_TUNNEL_DN ; +#ifdef DEBUG_GXS_TUNNEL + std::cerr << " This is client side. The tunnel will be re-openned automatically." << std::endl; +#endif + } - case RS_GXS_TUNNEL_FLAG_KEEP_ALIVE: + notifications.push_back(RS_GXS_TUNNEL_STATUS_REMOTELY_CLOSED) ; + } // nothing more to do, because the decryption routing will update the last_contact time when decrypting. + break ; + + case RS_GXS_TUNNEL_FLAG_KEEP_ALIVE: #ifdef DEBUG_GXS_TUNNEL - std::cerr << "GxsTunnelService::handleRecvGxsTunnelStatusItem(): received keep alive packet for inactive tunnel! peerId=" << cs->PeerId() << " tunnel=" << tunnel_id << std::endl; + std::cerr << "GxsTunnelService::handleRecvGxsTunnelStatusItem(): received keep alive packet for inactive tunnel! peerId=" << cs->PeerId() << " tunnel=" << tunnel_id << std::endl; #endif - break ; + break ; - case RS_GXS_TUNNEL_FLAG_ACK_DISTANT_CONNECTION: - { + case RS_GXS_TUNNEL_FLAG_ACK_DISTANT_CONNECTION: + { #ifdef DEBUG_GXS_TUNNEL - std::cerr << "Received ACK item from the distant peer!" << std::endl; + std::cerr << "Received ACK item from the distant peer!" << std::endl; #endif - // in this case we notify the clients using this tunnel. + // in this case we notify the clients using this tunnel. - notifications.push_back(RS_GXS_TUNNEL_STATUS_CAN_TALK) ; - } - break ; + notifications.push_back(RS_GXS_TUNNEL_STATUS_CAN_TALK) ; + } + break ; - default: - std::cerr << "(EE) unhandled tunnel status " << std::hex << cs->status << std::dec << std::endl; - break ; - } + default: + std::cerr << "(EE) unhandled tunnel status " << std::hex << cs->status << std::dec << std::endl; + break ; + } - // notify all clients + // notify all clients #ifdef DEBUG_GXS_TUNNEL - std::cerr << " notifying clients. Prending notifications: " << notifications.size() << std::endl; + std::cerr << " notifying clients. Prending notifications: " << notifications.size() << std::endl; #endif - if(notifications.size() > 0) - { - RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + if(notifications.size() > 0) + { + RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - std::map::iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; + std::map::iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; #ifdef DEBUG_GXS_TUNNEL - std::cerr << " " << it->second.client_services.size() << " client services for tunnel id " << tunnel_id << std::endl; + std::cerr << " " << it->second.client_services.size() << " client services for tunnel id " << tunnel_id << std::endl; #endif - for(std::set::const_iterator it2(it->second.client_services.begin());it2!=it->second.client_services.end();++it2) - { - std::map::const_iterator it3=mRegisteredServices.find(*it2) ; + for(std::set::const_iterator it2(it->second.client_services.begin());it2!=it->second.client_services.end();++it2) + { + std::map::const_iterator it3=mRegisteredServices.find(*it2) ; - if(it3 != mRegisteredServices.end()) - clients.insert(it3->second) ; - } - } + if(it3 != mRegisteredServices.end()) + clients.insert(it3->second) ; + } + } #ifdef DEBUG_GXS_TUNNEL - std::cerr << " notifying " << clients.size() << " clients." << std::endl; + std::cerr << " notifying " << clients.size() << " clients." << std::endl; #endif - for(std::set::const_iterator it(clients.begin());it!=clients.end();++it) - for(uint32_t i=0;inotifyTunnelStatus(tunnel_id,notifications[i]) ; + for(std::set::const_iterator it(clients.begin());it!=clients.end();++it) + for(uint32_t i=0;inotifyTunnelStatus(tunnel_id,notifications[i]) ; #ifdef DEBUG_GXS_TUNNEL - std::cerr << " notifying client " << (void*)(*it) << " of status " << notifications[i] << std::endl; + std::cerr << " notifying client " << (void*)(*it) << " of status " << notifications[i] << std::endl; #endif - } + } } bool p3GxsTunnelService::handleTunnelRequest(const RsFileHash& hash,const RsPeerId& /*peer_id*/) @@ -1422,87 +1433,87 @@ bool p3GxsTunnelService::getTunnelInfo(const RsGxsTunnelId& tunnel_id,GxsTunnelI bool p3GxsTunnelService::closeExistingTunnel(const RsGxsTunnelId& tunnel_id, uint32_t service_id) { - // two cases: - // - client needs to stop asking for tunnels => remove the hash from the list of tunnelled files - // - server needs to only close the window and let the tunnel die. But the window should only open - // if a message arrives. + // two cases: + // - client needs to stop asking for tunnels => remove the hash from the list of tunnelled files + // - server needs to only close the window and let the tunnel die. But the window should only open + // if a message arrives. - TurtleFileHash hash ; - TurtleVirtualPeerId vpid ; - bool close_tunnel = false ; - int direction ; - { - RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - std::map::iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; + TurtleFileHash hash ; + TurtleVirtualPeerId vpid ; + bool close_tunnel = false ; + int direction ; + { + RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + std::map::iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; - if(it == _gxs_tunnel_contacts.end()) - { - std::cerr << "(EE) Cannot close distant tunnel connection. No connection openned for tunnel id " << tunnel_id << std::endl; + if(it == _gxs_tunnel_contacts.end()) + { + std::cerr << "(EE) Cannot close distant tunnel connection. No connection openned for tunnel id " << tunnel_id << std::endl; - // We cannot stop tunnels, since their peer id is lost. Anyway, they'll die of starving. + // We cannot stop tunnels, since their peer id is lost. Anyway, they'll die of starving. - return false ; - } - vpid = it->second.virtual_peer_id ; + return false ; + } + vpid = it->second.virtual_peer_id ; - std::map::const_iterator it2 = _gxs_tunnel_virtual_peer_ids.find(vpid) ; + std::map::const_iterator it2 = _gxs_tunnel_virtual_peer_ids.find(vpid) ; - if(it2 != _gxs_tunnel_virtual_peer_ids.end()) - hash = it2->second.hash ; + if(it2 != _gxs_tunnel_virtual_peer_ids.end()) + hash = it2->second.hash ; - // check how many clients are used. If empty, close the tunnel + // check how many clients are used. If empty, close the tunnel - std::set::iterator it3 = it->second.client_services.find(service_id) ; + std::set::iterator it3 = it->second.client_services.find(service_id) ; - if(it3 == it->second.client_services.end()) - { - std::cerr << "(EE) service id not currently using that tunnel. This is an error." << std::endl; - return false; - } + if(it3 == it->second.client_services.end()) + { + std::cerr << "(EE) service id not currently using that tunnel. This is an error." << std::endl; + return false; + } - it->second.client_services.erase(it3) ; - direction = it->second.direction ; + it->second.client_services.erase(it3) ; + direction = it->second.direction ; - if(it->second.client_services.empty()) - close_tunnel = true ; - } + if(it->second.client_services.empty()) + close_tunnel = true ; + } - if(close_tunnel && direction == RsTurtleGenericTunnelItem::DIRECTION_SERVER) // nothing more to do for server side. - { - // send a status item saying that we're closing the connection + if(close_tunnel) + { + // send a status item saying that we're closing the connection #ifdef DEBUG_GXS_TUNNEL - std::cerr << " Sending a ACK to close the tunnel since we're managing it and it's not used by any service. tunnel id=." << tunnel_id << std::endl; + std::cerr << " Sending a ACK to close the tunnel since we're managing it and it's not used by any service. tunnel id=." << tunnel_id << std::endl; #endif - RsGxsTunnelStatusItem *cs = new RsGxsTunnelStatusItem ; + RsGxsTunnelStatusItem *cs = new RsGxsTunnelStatusItem ; - cs->status = RS_GXS_TUNNEL_FLAG_CLOSING_DISTANT_CONNECTION; - cs->PeerId(RsPeerId(tunnel_id)) ; + cs->status = RS_GXS_TUNNEL_FLAG_CLOSING_DISTANT_CONNECTION; + cs->PeerId(RsPeerId(tunnel_id)) ; - locked_sendEncryptedTunnelData(cs) ; // that needs to be done off-mutex and before we close the tunnel also ignoring failure. + locked_sendEncryptedTunnelData(cs) ; // that needs to be done off-mutex and before we close the tunnel also ignoring failure. + if(direction == RsTurtleGenericTunnelItem::DIRECTION_SERVER) // nothing more to do for server side. + { #ifdef DEBUG_GXS_TUNNEL - std::cerr << " This is client side. Stopping tunnel manageement for tunnel_id " << tunnel_id << std::endl; + std::cerr << " This is client side. Stopping tunnel manageement for tunnel_id " << tunnel_id << std::endl; #endif - mTurtle->stopMonitoringTunnels( hash ) ; // still valid if the hash is null - } + mTurtle->stopMonitoringTunnels( hash ) ; // still valid if the hash is null + } - if(close_tunnel) - { - RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - std::map::iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; + RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + std::map::iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; - if(it == _gxs_tunnel_contacts.end()) // server side. Nothing to do. - { - std::cerr << "(EE) Cannot close chat associated to tunnel id " << tunnel_id << ": not found." << std::endl; - return false ; - } + if(it == _gxs_tunnel_contacts.end()) // server side. Nothing to do. + { + std::cerr << "(EE) Cannot close chat associated to tunnel id " << tunnel_id << ": not found." << std::endl; + return false ; + } - _gxs_tunnel_contacts.erase(it) ; + _gxs_tunnel_contacts.erase(it) ; - // GxsTunnelService::removeVirtualPeerId() will be called by the turtle service. - } - return true ; + // GxsTunnelService::removeVirtualPeerId() will be called by the turtle service. + } + return true ; } bool p3GxsTunnelService::getTunnelsInfo(std::vector &infos) diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.h b/libretroshare/src/gxstunnel/p3gxstunnel.h index 488e3b914..67589f8e5 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.h +++ b/libretroshare/src/gxstunnel/p3gxstunnel.h @@ -28,10 +28,14 @@ // Generic tunnel service // // Preconditions: -// * multiple services can use the same tunnel -// * tunnels are automatically encrypted and ensure transport (items stored in a queue until ACKed by the other side) +// * the secured tunnel service takes care of: +// - tunnel health: tunnels are kept alive using special items, re-openned when necessary, etc. +// - transport: items are ACK-ed and re-sent if never received +// - encryption: items are all encrypted and authenticated using PFS(DH)+HMAC(sha1)+AES(128) // * each tunnel is associated to a specific GXS id on both sides. Consequently, services that request tunnels from different IDs to a // server for the same GXS id need to be handled correctly. +// * client services must register to the secured tunnel service if they want to use it. +// * multiple services can use the same tunnel. Items contain a service Id that is obtained when registering to the secured tunnel service. // // GUI // * the GUI should show for each tunnel: @@ -41,7 +45,7 @@ // - number of pending items (and total size) // - number ACKed items both ways. // -// we can use an additional tab "Authenticated tunnels" in the statistics->turtle window +// We can use an additional tab "Authenticated tunnels" in the statistics->turtle window for that purpose. // // Interaction with services: // @@ -52,14 +56,20 @@ // Data is send to a service ID (could be any existing service ID). The endpoint of the tunnel must register each service, in order to // allow the data to be transmitted/sent from/to that service. Otherwise an error is issued. // +// Encryption +// * the whole tunnel traffic is encrypted using AES-128 with random IV +// * a random key is established using DH key exchange for each connection (establishment of a new virtual peer) +// * encrypted items are authenticated with HMAC(sha1). +// * DH public keys are the only chunks of data that travel un-encrypted along the tunnel. They are +// signed to avoid any MITM interactions. No time-stamp is used in DH exchange since a replay attack would not work. +// // Algorithms // -// Tunnel establishment // * we need two layers: the turtle layer, and the GXS id layer. // - for each pair of GXS ids talking, a single turtle tunnel is used // - that tunnel can be shared by multiple services using it. // - services are responsoble for asking tunnels and also droppping them when unused. -// - at the turtle layer, the tunnel will be closed only when no service uses it. +// - at the turtle layer, the tunnel will be effectively closed only when no service uses it. // * IDs // TurtleVirtualPeerId: // - Used by tunnel service for each turtle tunnel @@ -72,25 +82,18 @@ // - accept virtual peers from turtle tunnel service. The hash for that VP only depends on the server GXS id at server side, which is our // own ID at server side, and destination ID at client side. What happens if two different clients request to talk to the same GXS id? (same hash) // They should use different virtual peers, so it should be ok. -// - multiple tunnels may end up to the same hash, but will correspond to different GXS tunnels since the GXS id in the other side is different. // // Turtle hash: [ 0 ---------------15 16---19 ] -// Destination Source +// Destination Random // // We Use 16 bytes to target the exact destination of the hash. The source part is just 4 arbitrary bytes that need to be different for all source // IDs that come from the same peer, which is quite likely to be sufficient. The real source of the tunnel will make itself known when sending the // DH key. // -// Another option is to use random bytes in 16-19. But then, we would digg multiple times different tunnels between the same two peers even when requesting -// a GXS tunnel for the same pair of GXS ids. Is that a problem? -// - that solves the problem of colliding source GXS ids (since 4 bytes is too small) -// - the DH will make it clear that we're talking to the same person if it already exist. -// // * at the GXS layer // - we should be able to have as many tunnels as they are different couples of GXS ids to interact. That means the tunnel should be determined // by a mix between our own GXS id and the GXS id we're talking to. That is what the TunnelVirtualPeer is. // - // // RequestTunnel(source_own_id,destination_id) - // | | @@ -108,14 +111,6 @@ // | | // +---------------- notify client service that Peer(destination_id, tunnel_hash) is ready to talk to | // - -// Notes -// * one other option would be to make the turtle hash depend on both GXS ids in a way that it is possible to find which are the two ids on the server side. -// but that would prevent the use of unknown IDs, which we would like to offer as well. -// Without this, it's not possible to request two tunnels to a same server GXS id but from a different client GXS id. Indeed, if the two hashes are the same, -// from the same peer, the tunnel names will be identical and so will be the virtual peer ids, if the route is the same (because of multi-tunneling, they -// will be different if the route is different). -// -// * #include #include diff --git a/retroshare-gui/src/gui/statistics/TurtleRouterStatistics.cpp b/retroshare-gui/src/gui/statistics/TurtleRouterStatistics.cpp index 242203388..a9713f0fa 100644 --- a/retroshare-gui/src/gui/statistics/TurtleRouterStatistics.cpp +++ b/retroshare-gui/src/gui/statistics/TurtleRouterStatistics.cpp @@ -195,8 +195,8 @@ TurtleRouterStatistics::TurtleRouterStatistics(QWidget *parent) _tunnel_statistics_F->setFrameStyle(QFrame::NoFrame); _tunnel_statistics_F->setFocusPolicy(Qt::NoFocus); - routertabWidget->addTab(new TurtleRouterDialog(),QString(tr("Tunnels"))); - routertabWidget->addTab(new GxsTunnelsDialog(),QString(tr("Authenticated pipes"))); + routertabWidget->addTab(new TurtleRouterDialog(),QString(tr("Anonymous tunnels"))); + routertabWidget->addTab(new GxsTunnelsDialog(),QString(tr("Authenticated tunnels"))); float fontHeight = QFontMetricsF(font()).height(); float fact = fontHeight/14.0; From 7cd880e1e4bb11e16470d3b8600d515389290dd3 Mon Sep 17 00:00:00 2001 From: electron128 Date: Sat, 5 Dec 2015 17:00:57 +0100 Subject: [PATCH 22/26] removed member gxs_id from ChatId class, because ChatId now uses tunnel ids stored in distant_chat_id for distant chat. reverted naming confusion in in libresapi ChatHandler and fixed author of distant chat messages (distant chat is still unfinished) --- libresapi/src/api/ChatHandler.cpp | 20 +++++------ libresapi/src/api/ChatHandler.h | 6 ++-- libretroshare/src/retroshare/rsmsgs.h | 4 --- libretroshare/src/rsserver/p3msgs.cc | 21 ----------- .../src/gui/common/AvatarWidget.cpp | 36 +++++++++++++------ retroshare-gui/src/gui/common/AvatarWidget.h | 2 ++ retroshare-gui/src/gui/feeds/MsgItem.cpp | 6 ++-- retroshare-gui/src/gui/feeds/MsgItem.h | 1 - .../src/gui/toaster/ChatLobbyToaster.cpp | 2 +- 9 files changed, 43 insertions(+), 55 deletions(-) diff --git a/libresapi/src/api/ChatHandler.cpp b/libresapi/src/api/ChatHandler.cpp index a99759990..b9f7bda4b 100644 --- a/libresapi/src/api/ChatHandler.cpp +++ b/libresapi/src/api/ChatHandler.cpp @@ -81,8 +81,8 @@ StreamBase& operator << (StreamBase& left, ChatHandler::Lobby& l) << makeKeyValueReference("subscribed", l.subscribed) << makeKeyValueReference("auto_subscribe", l.auto_subscribe) << makeKeyValueReference("is_private", l.is_private) - << makeKeyValueReference("distant_chat_id", l.distant_chat_id) - << makeKeyValueReference("is_broadcast", l.is_broadcast); + << makeKeyValueReference("is_broadcast", l.is_broadcast) + << makeKeyValueReference("gxs_id", l.gxs_id); return left; } @@ -167,8 +167,8 @@ void ChatHandler::tick() l.subscribed = true; l.auto_subscribe = info.lobby_flags & RS_CHAT_LOBBY_FLAGS_AUTO_SUBSCRIBE; l.is_private = !(info.lobby_flags & RS_CHAT_LOBBY_FLAGS_PUBLIC); - l.distant_chat_id.clear() ; l.is_broadcast = false; + l.gxs_id = info.gxs_id; lobbies.push_back(l); } } @@ -200,8 +200,8 @@ void ChatHandler::tick() l.subscribed = false; l.auto_subscribe = info.lobby_flags & RS_CHAT_LOBBY_FLAGS_AUTO_SUBSCRIBE; l.is_private = !(info.lobby_flags & RS_CHAT_LOBBY_FLAGS_PUBLIC); - l.distant_chat_id.clear(); l.is_broadcast = false; + l.gxs_id = RsGxsId(); lobbies.push_back(l); } } @@ -233,11 +233,11 @@ void ChatHandler::tick() std::cerr << "(EE) cannot get info for distant chat peer " << msg.chat_id.toDistantChatId() << std::endl; continue ; } - - author_id = dcpinfo.to_id.toStdString(); + RsIdentityDetails details; - if(!gxs_id_failed && mRsIdentity->getIdDetails(dcpinfo.to_id, details)) + if(!gxs_id_failed && mRsIdentity->getIdDetails(msg.incoming? dcpinfo.to_id: dcpinfo.own_id, details)) { + author_id = details.mId.toStdString(); author_name = details.mNickname; } else @@ -301,10 +301,10 @@ void ChatHandler::tick() RsIdentityDetails details; DistantChatPeerInfo dcpinfo ; - if(!gxs_id_failed && rsMsgs->getDistantChatStatus(msg.chat_id.toDistantChatId(),dcpinfo) - && mRsIdentity->getIdDetails(dcpinfo.to_id, details)) + if(!gxs_id_failed && rsMsgs->getDistantChatStatus(msg.chat_id.toDistantChatId(),dcpinfo) + && mRsIdentity->getIdDetails(msg.incoming? dcpinfo.to_id: dcpinfo.own_id, details)) { - info.remote_author_id = msg.chat_id.toGxsId().toStdString(); + info.remote_author_id = details.mId.toStdString(); info.remote_author_name = details.mNickname; } else diff --git a/libresapi/src/api/ChatHandler.h b/libresapi/src/api/ChatHandler.h index 1d4ed221f..bb15cf2f1 100644 --- a/libresapi/src/api/ChatHandler.h +++ b/libresapi/src/api/ChatHandler.h @@ -66,7 +66,7 @@ public: bool is_private; bool is_broadcast; - RsGxsId distant_chat_id;// for subscribed lobbies: the id we use to write messages + RsGxsId gxs_id;// for subscribed lobbies: the id we use to write messages bool operator==(const Lobby& l) const { @@ -76,8 +76,8 @@ public: && subscribed == l.subscribed && auto_subscribe == l.auto_subscribe && is_private == l.is_private - && id == l.id - && is_broadcast == l.is_broadcast; + && is_broadcast == l.is_broadcast + && gxs_id == l.gxs_id; } }; diff --git a/libretroshare/src/retroshare/rsmsgs.h b/libretroshare/src/retroshare/rsmsgs.h index 4eadb79d1..edeb0a66e 100644 --- a/libretroshare/src/retroshare/rsmsgs.h +++ b/libretroshare/src/retroshare/rsmsgs.h @@ -279,7 +279,6 @@ class ChatId public: ChatId(); explicit ChatId(RsPeerId id); - explicit ChatId(RsGxsId id); explicit ChatId(ChatLobbyId id); explicit ChatId(DistantChatPeerId id); explicit ChatId(std::string str); @@ -295,7 +294,6 @@ public: bool isPeerId() const; bool isDistantChatId() const; bool isLobbyId() const; - bool isGxsId() const; bool isBroadcast() const; RsPeerId toPeerId() const; @@ -312,7 +310,6 @@ private: TYPE_PRIVATE, // private chat with directly connected friend, peer_id is valid TYPE_PRIVATE_DISTANT, // private chat with distant peer, gxs_id is valid TYPE_LOBBY, // chat lobby id, lobby_id is valid - TYPE_GXS_ID, // TYPE_BROADCAST // message to/from all connected peers }; @@ -320,7 +317,6 @@ private: RsPeerId peer_id; DistantChatPeerId distant_chat_id; ChatLobbyId lobby_id; - RsGxsId gxs_id; }; class ChatMessage diff --git a/libretroshare/src/rsserver/p3msgs.cc b/libretroshare/src/rsserver/p3msgs.cc index b9690c95d..e4986467e 100644 --- a/libretroshare/src/rsserver/p3msgs.cc +++ b/libretroshare/src/rsserver/p3msgs.cc @@ -58,13 +58,6 @@ ChatId::ChatId(): } -ChatId::ChatId(RsGxsId id): - lobby_id(0) -{ - type = TYPE_GXS_ID; - gxs_id = id; -} - ChatId::ChatId(RsPeerId id): lobby_id(0) { @@ -244,10 +237,6 @@ bool ChatId::isLobbyId() const { return type == TYPE_LOBBY; } -bool ChatId::isGxsId() const -{ - return type == TYPE_GXS_ID; -} bool ChatId::isBroadcast() const { return type == TYPE_BROADCAST; @@ -263,16 +252,6 @@ RsPeerId ChatId::toPeerId() const } } -RsGxsId ChatId::toGxsId() const -{ - if(type == TYPE_GXS_ID) - return gxs_id; - else - { - std::cerr << "ChatId Warning: conversation to gxs_id requested, but type is different. Current value=\"" << toStdString() << "\"" << std::endl; - return RsGxsId(); - } -} DistantChatPeerId ChatId::toDistantChatId() const { if(type == TYPE_PRIVATE_DISTANT) diff --git a/retroshare-gui/src/gui/common/AvatarWidget.cpp b/retroshare-gui/src/gui/common/AvatarWidget.cpp index 2ed494184..71147d7b6 100644 --- a/retroshare-gui/src/gui/common/AvatarWidget.cpp +++ b/retroshare-gui/src/gui/common/AvatarWidget.cpp @@ -124,19 +124,33 @@ void AvatarWidget::setFrameType(FrameType type) void AvatarWidget::setId(const ChatId &id) { mId = id; + mGxsId.clear(); setPixmap(QPixmap()); if (id.isNotSet()) { setEnabled(false); } - - if(mId.isGxsId()) - std::cerr << "(EE) AvatarWidget should not be set to a GXS id." << std::endl; refreshAvatarImage(); refreshStatus(); } + +void AvatarWidget::setGxsId(const RsGxsId &id) +{ + mId = ChatId(); + mGxsId = id; + + setPixmap(QPixmap()); + + if (id.isNull()) { + setEnabled(false); + } + + refreshAvatarImage(); + refreshStatus(); +} + void AvatarWidget::setOwnId() { mFlag.isOwnId = true; @@ -242,6 +256,14 @@ void AvatarWidget::updateAvatar(const QString &peerId) } void AvatarWidget::refreshAvatarImage() { + if (mGxsId.isNull()==false) + { + QPixmap avatar; + + AvatarDefs::getAvatarFromGxsId(mGxsId, avatar, defaultAvatar); + setPixmap(avatar); + return; + } if (mId.isNotSet()) { QPixmap avatar(defaultAvatar); @@ -262,14 +284,6 @@ void AvatarWidget::refreshAvatarImage() setPixmap(avatar); return; } -// else if (mId.isGxsId()) -// { -// QPixmap avatar; -// -// AvatarDefs::getAvatarFromGxsId(mId.toGxsId(), avatar, defaultAvatar); -// setPixmap(avatar); -// return; -// } else if (mId.isDistantChatId()) { QPixmap avatar; diff --git a/retroshare-gui/src/gui/common/AvatarWidget.h b/retroshare-gui/src/gui/common/AvatarWidget.h index 1c140f469..de15ef066 100644 --- a/retroshare-gui/src/gui/common/AvatarWidget.h +++ b/retroshare-gui/src/gui/common/AvatarWidget.h @@ -50,6 +50,7 @@ public: QString frameState(); void setFrameType(FrameType type); void setId(const ChatId& id) ; + void setGxsId(const RsGxsId& id) ; void setOwnId(); void setDefaultAvatar(const QString &avatar_file_name); @@ -70,6 +71,7 @@ private: Ui::AvatarWidget *ui; ChatId mId; + RsGxsId mGxsId; struct { bool isOwnId : 1; diff --git a/retroshare-gui/src/gui/feeds/MsgItem.cpp b/retroshare-gui/src/gui/feeds/MsgItem.cpp index cb44de952..93b9d3e8c 100644 --- a/retroshare-gui/src/gui/feeds/MsgItem.cpp +++ b/retroshare-gui/src/gui/feeds/MsgItem.cpp @@ -88,11 +88,9 @@ void MsgItem::updateItemStatic() /* get peer Id */ if(mi.msgflags & RS_MSG_SIGNED) - mPeerId = ChatId(mi.rsgxsid_srcId); + avatar->setGxsId(mi.rsgxsid_srcId); else - mPeerId = ChatId(mi.rspeerid_srcId); - - avatar->setId(mPeerId); + avatar->setId(ChatId(mi.rspeerid_srcId)); QString title; QString srcName; diff --git a/retroshare-gui/src/gui/feeds/MsgItem.h b/retroshare-gui/src/gui/feeds/MsgItem.h index dd82dfb50..9b036260e 100644 --- a/retroshare-gui/src/gui/feeds/MsgItem.h +++ b/retroshare-gui/src/gui/feeds/MsgItem.h @@ -64,7 +64,6 @@ private: FeedHolder *mParent; uint32_t mFeedId; - ChatId mPeerId; std::string mMsgId; QString mMsg; diff --git a/retroshare-gui/src/gui/toaster/ChatLobbyToaster.cpp b/retroshare-gui/src/gui/toaster/ChatLobbyToaster.cpp index 882004975..25d5c2d2a 100644 --- a/retroshare-gui/src/gui/toaster/ChatLobbyToaster.cpp +++ b/retroshare-gui/src/gui/toaster/ChatLobbyToaster.cpp @@ -45,7 +45,7 @@ ChatLobbyToaster::ChatLobbyToaster(const ChatLobbyId &lobby_id, const RsGxsId &s if(!rsIdentity->getIdDetails(sender_id, idd)) return; - ui.avatarWidget->setId(ChatId(sender_id)); + ui.avatarWidget->setGxsId(sender_id); QString lobbyName = RsHtml::plainText(idd.mNickname); From e2542a6c50ecffa0fa6bf7517a722901e9a161ca Mon Sep 17 00:00:00 2001 From: Cyril Soler Date: Mon, 7 Dec 2015 10:02:04 -0500 Subject: [PATCH 23/26] added missing check after deserialisation of grouter item which caused a crash when receiving a malformed message data --- libretroshare/src/grouter/p3grouter.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libretroshare/src/grouter/p3grouter.cc b/libretroshare/src/grouter/p3grouter.cc index 8ed41178c..cf12bfb53 100644 --- a/libretroshare/src/grouter/p3grouter.cc +++ b/libretroshare/src/grouter/p3grouter.cc @@ -510,6 +510,12 @@ void p3GRouter::receiveTurtleData(RsTurtleGenericTunnelItem *gitem,const RsFileH RsItem *itm = RsGRouterSerialiser().deserialise(item->data_bytes,&item->data_size) ; +if(itm == NULL) +{ + std::cerr << "(EE) p3GRouter::receiveTurtleData(): cannot de-serialise data. Somthing wrong in the format. Item data (size="<< item->data_size << "): " << RsUtil::BinToHex((char*)item->data_bytes,item->data_size) << std::endl; + return ; +} + itm->PeerId(virtual_peer_id) ; // At this point we can have either a transaction chunk, or a transaction ACK. From 4724007c653dcb07fe8a2e32bfffd5ad5aeaed63 Mon Sep 17 00:00:00 2001 From: defnax Date: Mon, 7 Dec 2015 17:11:25 +0100 Subject: [PATCH 24/26] Changed Context Menu order issue: #187 --- retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp index cd873b6d0..5785d68fb 100644 --- a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp +++ b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp @@ -259,6 +259,13 @@ void GxsGroupFrameDialog::groupTreeCustomPopupMenu(QPoint point) QMenu contextMnu(this); QAction *action; + + if (mMessageWidget) { + action = contextMnu.addAction(QIcon(IMAGE_TABNEW), tr("Open in new tab"), this, SLOT(openInNewTab())); + if (mGroupId.isNull() || messageWidget(mGroupId, true)) { + action->setEnabled(false); + } + } if (isSubscribed) { action = contextMnu.addAction(QIcon(IMAGE_UNSUBSCRIBE), tr("Unsubscribe"), this, SLOT(unsubscribeGroup())); @@ -268,13 +275,6 @@ void GxsGroupFrameDialog::groupTreeCustomPopupMenu(QPoint point) action->setDisabled (mGroupId.isNull() || IS_GROUP_SUBSCRIBED(subscribeFlags)); } - if (mMessageWidget) { - action = contextMnu.addAction(QIcon(IMAGE_TABNEW), tr("Open in new tab"), this, SLOT(openInNewTab())); - if (mGroupId.isNull() || messageWidget(mGroupId, true)) { - action->setEnabled(false); - } - } - contextMnu.addSeparator(); contextMnu.addAction(QIcon(icon(ICON_NEW)), text(TEXT_NEW), this, SLOT(newGroup())); From 0957e7068a0da89ae1fde119eb228f558201307a Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 7 Dec 2015 22:39:45 -0500 Subject: [PATCH 25/26] changed the method of computation for tunnel hashes in global router in order to avoid conflict with GxsTunnel service (breaks compatibility of distant message sending) --- libretroshare/src/grouter/p3grouter.cc | 29 +++++++++++++++++++------- libretroshare/src/grouter/p3grouter.h | 2 +- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/libretroshare/src/grouter/p3grouter.cc b/libretroshare/src/grouter/p3grouter.cc index cf12bfb53..ddb6dd004 100644 --- a/libretroshare/src/grouter/p3grouter.cc +++ b/libretroshare/src/grouter/p3grouter.cc @@ -316,6 +316,7 @@ bool p3GRouter::registerKey(const RsGxsId& authentication_key,const GRouterServi grouter_debug() << " Auth GXS Id : " << authentication_key << std::endl; grouter_debug() << " Client id : " << std::hex << client_id << std::dec << std::endl; grouter_debug() << " Description : " << info.description_string << std::endl; + grouter_debug() << " Hash : " << hash << std::endl; #endif return true ; @@ -1680,10 +1681,14 @@ bool p3GRouter::locked_getClientAndServiceId(const TurtleFileHash& hash, const R { client = NULL ; service_id = 0; - RsGxsId gxs_id ; - makeGxsIdAndClientId(hash,gxs_id,service_id) ; - + + if(!locked_getGxsIdAndClientId(hash,gxs_id,service_id)) + { + std::cerr << " p3GRouter::ERROR: locked_getGxsIdAndClientId(): no key registered for hash " << hash << std::endl; + return false ; + } + if(gxs_id != destination_key) { std::cerr << " ERROR: verification (destination) GXS key " << destination_key << " does not match key from hash " << gxs_id << std::endl; @@ -2019,15 +2024,25 @@ Sha1CheckSum p3GRouter::makeTunnelHash(const RsGxsId& destination,const GRouterS bytes[18] = (client >> 8) & 0xff ; bytes[19] = client & 0xff ; - return Sha1CheckSum(bytes) ; + return RsDirUtil::sha1sum(bytes,20) ; } -void p3GRouter::makeGxsIdAndClientId(const TurtleFileHash& sum,RsGxsId& gxs_id,GRouterServiceId& client_id) +bool p3GRouter::locked_getGxsIdAndClientId(const TurtleFileHash& sum,RsGxsId& gxs_id,GRouterServiceId& client_id) { assert( gxs_id.SIZE_IN_BYTES == 16) ; assert(Sha1CheckSum::SIZE_IN_BYTES == 20) ; - gxs_id = RsGxsId(sum.toByteArray());// takes the first 16 bytes - client_id = sum.toByteArray()[19] + (sum.toByteArray()[18] << 8) ; + //gxs_id = RsGxsId(sum.toByteArray());// takes the first 16 bytes + //client_id = sum.toByteArray()[19] + (sum.toByteArray()[18] << 8) ; + + std::map::const_iterator it = _owned_key_ids.find(sum); + + if(it == _owned_key_ids.end()) + return false ; + + gxs_id = it->second.authentication_key ; + client_id = it->second.service_id ; + + return true ; } bool p3GRouter::loadList(std::list& items) { diff --git a/libretroshare/src/grouter/p3grouter.h b/libretroshare/src/grouter/p3grouter.h index 98beac792..6a73253cf 100644 --- a/libretroshare/src/grouter/p3grouter.h +++ b/libretroshare/src/grouter/p3grouter.h @@ -269,8 +269,8 @@ private: bool decryptDataItem(RsGRouterGenericDataItem *item) ; static Sha1CheckSum makeTunnelHash(const RsGxsId& destination,const GRouterServiceId& client); - static void makeGxsIdAndClientId(const TurtleFileHash &sum,RsGxsId& gxs_id,GRouterServiceId& client_id); + bool locked_getGxsIdAndClientId(const TurtleFileHash &sum,RsGxsId& gxs_id,GRouterServiceId& client_id); bool locked_sendTransactionData(const RsPeerId& pid,const RsGRouterTransactionItem& item); void locked_collectAvailableFriends(const GRouterKeyId &gxs_id,std::list& friend_peers, const std::set& incoming_routes,bool is_origin); From 893f178ce1fac1eeed89a7e423b8ef1821b82d6d Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 7 Dec 2015 23:09:44 -0500 Subject: [PATCH 26/26] changed GxsTunnel method for computing turtle hash, to avoid crashing old peers --- libretroshare/src/gxstunnel/p3gxstunnel.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.cc b/libretroshare/src/gxstunnel/p3gxstunnel.cc index 7c571e29e..f7be21db7 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.cc +++ b/libretroshare/src/gxstunnel/p3gxstunnel.cc @@ -1389,14 +1389,14 @@ TurtleFileHash p3GxsTunnelService::randomHashFromDestinationGxsId(const RsGxsId& assert(Sha1CheckSum::SIZE_IN_BYTES == 20) ; uint8_t bytes[20] ; - memcpy(bytes,destination.toByteArray(),16) ; + memcpy(&bytes[4],destination.toByteArray(),16) ; - RAND_bytes(&bytes[16],4) ; // fill the last bytes with random crap. Very important to allow tunnels from different sources and statistically avoid collisions. + RAND_bytes(&bytes[0],4) ; // fill the 4 first bytes with random crap. Very important to allow tunnels from different sources and statistically avoid collisions. // We could rehash this, with a secret key to get a HMAC. That would allow to publish secret distant chat // passphrases. I'll do this later if needed. - return Sha1CheckSum(bytes) ; + return Sha1CheckSum(bytes) ; // this does not compute a hash, and that is on purpose. } RsGxsId p3GxsTunnelService::destinationGxsIdFromHash(const TurtleFileHash& sum) @@ -1404,7 +1404,7 @@ RsGxsId p3GxsTunnelService::destinationGxsIdFromHash(const TurtleFileHash& sum) assert( RsGxsId::SIZE_IN_BYTES == 16) ; assert(Sha1CheckSum::SIZE_IN_BYTES == 20) ; - return RsGxsId(sum.toByteArray());// takes the first 16 bytes + return RsGxsId(&sum.toByteArray()[4]);// takes the last 16 bytes } bool p3GxsTunnelService::getTunnelInfo(const RsGxsTunnelId& tunnel_id,GxsTunnelInfo& info)