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.