mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-07-22 22:21:09 -04:00
Merged branch v0.5-GenericTunneling into trunk (Rev. 6284 to 6410).
- adds turtle router as a generic tunneling service - made ftServer a client of the service. Now turtle file items are handled in ftServer - added new client: p3MsgService to send/recv pgp-encrypted distant messages - added new client: p3ChatService to perform private (AES-encrypted) distant chat through tunnels. - The GUI is disabled for now, since it needs some polishing before being fully usable. git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@6411 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
commit
dc2521cf71
62 changed files with 5031 additions and 1989 deletions
|
@ -24,11 +24,18 @@
|
|||
*/
|
||||
#include <math.h>
|
||||
|
||||
#include "openssl/rand.h"
|
||||
#include "pgp/rscertificate.h"
|
||||
#include "pqi/authgpg.h"
|
||||
#include "util/rsdir.h"
|
||||
#include "util/radix64.h"
|
||||
#include "util/rsaes.h"
|
||||
#include "util/rsrandom.h"
|
||||
#include "util/rsstring.h"
|
||||
#include "turtle/p3turtle.h"
|
||||
#include "retroshare/rsiface.h"
|
||||
#include "retroshare/rspeers.h"
|
||||
#include "retroshare/rsstatus.h"
|
||||
#include "pqi/pqibin.h"
|
||||
#include "pqi/pqinotify.h"
|
||||
#include "pqi/pqistore.h"
|
||||
|
@ -40,6 +47,7 @@
|
|||
|
||||
/****
|
||||
* #define CHAT_DEBUG 1
|
||||
* #define DEBUG_DISTANT_CHAT 1
|
||||
****/
|
||||
|
||||
static const int CONNECTION_CHALLENGE_MAX_COUNT = 20 ; // sends a connexion challenge every 20 messages
|
||||
|
@ -52,18 +60,30 @@ static const time_t MAX_DELAY_BETWEEN_LOBBY_KEEP_ALIVE = 120 ; // send keep al
|
|||
static const time_t MAX_KEEP_PUBLIC_LOBBY_RECORD = 60 ; // keep inactive lobbies records for 60 secs max.
|
||||
static const time_t MIN_DELAY_BETWEEN_PUBLIC_LOBBY_REQ = 20 ; // don't ask for lobby list more than once every 30 secs.
|
||||
|
||||
static const time_t DISTANT_CHAT_CLEANING_PERIOD = 60 ; // don't ask for lobby list more than once every 30 secs.
|
||||
static const uint32_t DISTANT_CHAT_AES_KEY_SIZE = 16 ; // size of AES encryption key for distant chat.
|
||||
static const uint32_t DISTANT_CHAT_HASH_SIZE = 20 ; // This is sha1 size in bytes.
|
||||
|
||||
p3ChatService::p3ChatService(p3LinkMgr *lm, p3HistoryMgr *historyMgr)
|
||||
:p3Service(RS_SERVICE_TYPE_CHAT), p3Config(CONFIG_TYPE_CHAT), mChatMtx("p3ChatService"), mLinkMgr(lm) , mHistoryMgr(historyMgr)
|
||||
{
|
||||
addSerialType(new RsChatSerialiser());
|
||||
|
||||
_serializer = new RsChatSerialiser() ;
|
||||
_own_avatar = NULL ;
|
||||
_custom_status_string = "" ;
|
||||
_time_shift_average = 0.0f ;
|
||||
_default_nick_name = rsPeers->getPeerName(rsPeers->getOwnId());
|
||||
_should_reset_lobby_counts = false ;
|
||||
mTurtle = NULL ;
|
||||
|
||||
last_visible_lobby_info_request_time = 0 ;
|
||||
|
||||
addSerialType(_serializer) ;
|
||||
}
|
||||
|
||||
void p3ChatService::connectToTurtleRouter(p3turtle *tr)
|
||||
{
|
||||
mTurtle = tr ;
|
||||
tr->registerTunnelService(this) ;
|
||||
}
|
||||
|
||||
int p3ChatService::tick()
|
||||
|
@ -71,15 +91,21 @@ int p3ChatService::tick()
|
|||
if(receivedItems())
|
||||
receiveChatQueue();
|
||||
|
||||
static time_t last_clean_time = 0 ;
|
||||
static time_t last_clean_time_lobby = 0 ;
|
||||
static time_t last_clean_time_dchat = 0 ;
|
||||
|
||||
time_t now = time(NULL) ;
|
||||
|
||||
if(last_clean_time + LOBBY_CACHE_CLEANING_PERIOD < now)
|
||||
if(last_clean_time_lobby + LOBBY_CACHE_CLEANING_PERIOD < now)
|
||||
{
|
||||
cleanLobbyCaches() ;
|
||||
last_clean_time = now ;
|
||||
last_clean_time_lobby = now ;
|
||||
}
|
||||
if(last_clean_time_dchat + DISTANT_CHAT_CLEANING_PERIOD < now)
|
||||
{
|
||||
cleanDistantChatInvites() ;
|
||||
last_clean_time_dchat = now ;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -221,10 +247,27 @@ void p3ChatService::sendStatusString( const std::string& id , const std::string&
|
|||
std::cerr << "sending chat status packet:" << std::endl ;
|
||||
cs->print(std::cerr) ;
|
||||
#endif
|
||||
sendItem(cs);
|
||||
sendPrivateChatItem(cs);
|
||||
}
|
||||
}
|
||||
|
||||
void p3ChatService::sendPrivateChatItem(RsChatItem *item)
|
||||
{
|
||||
bool found = false ;
|
||||
|
||||
{
|
||||
RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/
|
||||
|
||||
if(_distant_chat_peers.find(item->PeerId()) != _distant_chat_peers.end())
|
||||
found = true ;
|
||||
}
|
||||
|
||||
if(found)
|
||||
sendTurtleData(item) ;
|
||||
else
|
||||
sendItem(item) ;
|
||||
}
|
||||
|
||||
void p3ChatService::checkSizeAndSendMessage_deprecated(RsChatMsgItem *msg)
|
||||
{
|
||||
// We check the message item, and possibly split it into multiple messages, if the message is too big.
|
||||
|
@ -248,9 +291,9 @@ void p3ChatService::checkSizeAndSendMessage_deprecated(RsChatMsgItem *msg)
|
|||
// Indicate that the message is to be continued.
|
||||
//
|
||||
item->chatFlags |= RS_CHAT_FLAG_PARTIAL_MESSAGE ;
|
||||
sendItem(item) ;
|
||||
sendPrivateChatItem(item) ;
|
||||
}
|
||||
sendItem(msg) ;
|
||||
sendPrivateChatItem(msg) ;
|
||||
}
|
||||
// This function should be used for all types of chat messages. But this requires a non backward compatible change in
|
||||
// chat protocol. To be done for version 0.6
|
||||
|
@ -374,6 +417,18 @@ bool p3ChatService::isLobbyId(const std::string& id,ChatLobbyId& lobby_id)
|
|||
return false ;
|
||||
}
|
||||
|
||||
bool p3ChatService::isOnline(const std::string& id)
|
||||
{
|
||||
// check if the id is a tunnel id or a peer id.
|
||||
|
||||
uint32_t status ;
|
||||
std::string pgp_id ;
|
||||
|
||||
if(!getDistantChatStatus(id,status,pgp_id))
|
||||
return mLinkMgr->isOnline(id) ;
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
bool p3ChatService::sendPrivateChat(const std::string &id, const std::wstring &msg)
|
||||
{
|
||||
|
@ -398,7 +453,8 @@ bool p3ChatService::sendPrivateChat(const std::string &id, const std::wstrin
|
|||
ci->recvTime = ci->sendTime;
|
||||
ci->message = msg;
|
||||
|
||||
if (!mLinkMgr->isOnline(id)) {
|
||||
if(!isOnline(id))
|
||||
{
|
||||
/* peer is offline, add to outgoing list */
|
||||
{
|
||||
RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/
|
||||
|
@ -471,7 +527,7 @@ bool p3ChatService::sendPrivateChat(const std::string &id, const std::wstrin
|
|||
#endif
|
||||
RsChatStatusItem *cs = makeOwnCustomStateStringItem() ;
|
||||
cs->PeerId(id) ;
|
||||
sendItem(cs) ;
|
||||
sendPrivateChatItem(cs) ;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -608,20 +664,24 @@ void p3ChatService::receiveChatQueue()
|
|||
RsItem *item ;
|
||||
|
||||
while(NULL != (item=recvItem()))
|
||||
{
|
||||
#ifdef CHAT_DEBUG
|
||||
std::cerr << "p3ChatService::receiveChatQueue() Item:" << (void*)item << std::endl ;
|
||||
#endif
|
||||
// RsChatMsgItems needs dynamic_cast, since they have derived siblings.
|
||||
//
|
||||
RsChatMsgItem *ci = dynamic_cast<RsChatMsgItem*>(item) ;
|
||||
if(ci != NULL)
|
||||
{
|
||||
if(! handleRecvChatMsgItem(ci))
|
||||
delete ci ;
|
||||
handleIncomingItem(item) ;
|
||||
}
|
||||
|
||||
continue ; // don't delete! It's handled by handleRecvChatMsgItem in some specific cases only.
|
||||
}
|
||||
void p3ChatService::handleIncomingItem(RsItem *item)
|
||||
{
|
||||
#ifdef CHAT_DEBUG
|
||||
std::cerr << "p3ChatService::receiveChatQueue() Item:" << (void*)item << std::endl ;
|
||||
#endif
|
||||
// RsChatMsgItems needs dynamic_cast, since they have derived siblings.
|
||||
//
|
||||
RsChatMsgItem *ci = dynamic_cast<RsChatMsgItem*>(item) ;
|
||||
if(ci != NULL)
|
||||
{
|
||||
if(! handleRecvChatMsgItem(ci))
|
||||
delete ci ;
|
||||
|
||||
return ; // don't delete! It's handled by handleRecvChatMsgItem in some specific cases only.
|
||||
}
|
||||
|
||||
switch(item->PacketSubType())
|
||||
{
|
||||
|
@ -647,7 +707,6 @@ void p3ChatService::receiveChatQueue()
|
|||
}
|
||||
}
|
||||
delete item ;
|
||||
}
|
||||
}
|
||||
|
||||
void p3ChatService::handleRecvChatLobbyListRequest(RsChatLobbyListRequestItem *clr)
|
||||
|
@ -1479,17 +1538,19 @@ void p3ChatService::getOwnAvatarJpegData(unsigned char *& data,int& size)
|
|||
|
||||
std::string p3ChatService::getCustomStateString(const std::string& peer_id)
|
||||
{
|
||||
// should be a Mutex here.
|
||||
RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/
|
||||
|
||||
std::map<std::string,StateStringInfo>::iterator it = _state_strings.find(peer_id) ;
|
||||
|
||||
// has it. Return it strait away.
|
||||
//
|
||||
if(it!=_state_strings.end())
|
||||
{
|
||||
it->second._peer_is_new = false ;
|
||||
return it->second._custom_status_string ;
|
||||
// should be a Mutex here.
|
||||
RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/
|
||||
|
||||
std::map<std::string,StateStringInfo>::iterator it = _state_strings.find(peer_id) ;
|
||||
|
||||
// has it. Return it strait away.
|
||||
//
|
||||
if(it!=_state_strings.end())
|
||||
{
|
||||
it->second._peer_is_new = false ;
|
||||
return it->second._custom_status_string ;
|
||||
}
|
||||
}
|
||||
|
||||
sendCustomStateRequest(peer_id);
|
||||
|
@ -1498,33 +1559,35 @@ std::string p3ChatService::getCustomStateString(const std::string& peer_id)
|
|||
|
||||
void p3ChatService::getAvatarJpegData(const std::string& peer_id,unsigned char *& data,int& size)
|
||||
{
|
||||
// should be a Mutex here.
|
||||
RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/
|
||||
|
||||
std::map<std::string,AvatarInfo *>::const_iterator it = _avatars.find(peer_id) ;
|
||||
|
||||
#ifdef CHAT_DEBUG
|
||||
std::cerr << "p3chatservice:: avatar for peer " << peer_id << " requested from above. " << std::endl ;
|
||||
#endif
|
||||
// has avatar. Return it straight away.
|
||||
//
|
||||
if(it!=_avatars.end())
|
||||
{
|
||||
uint32_t s=0 ;
|
||||
it->second->toUnsignedChar(data,s) ;
|
||||
size = s ;
|
||||
it->second->_peer_is_new = false ;
|
||||
#ifdef CHAT_DEBUG
|
||||
std::cerr << "Already has avatar. Returning it" << std::endl ;
|
||||
#endif
|
||||
return ;
|
||||
} else {
|
||||
#ifdef CHAT_DEBUG
|
||||
std::cerr << "No avatar for this peer. Requesting it by sending request packet." << std::endl ;
|
||||
#endif
|
||||
}
|
||||
// should be a Mutex here.
|
||||
RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/
|
||||
|
||||
sendAvatarRequest(peer_id);
|
||||
std::map<std::string,AvatarInfo *>::const_iterator it = _avatars.find(peer_id) ;
|
||||
|
||||
#ifdef CHAT_DEBUG
|
||||
std::cerr << "p3chatservice:: avatar for peer " << peer_id << " requested from above. " << std::endl ;
|
||||
#endif
|
||||
// has avatar. Return it straight away.
|
||||
//
|
||||
if(it!=_avatars.end())
|
||||
{
|
||||
uint32_t s=0 ;
|
||||
it->second->toUnsignedChar(data,s) ;
|
||||
size = s ;
|
||||
it->second->_peer_is_new = false ;
|
||||
#ifdef CHAT_DEBUG
|
||||
std::cerr << "Already has avatar. Returning it" << std::endl ;
|
||||
#endif
|
||||
return ;
|
||||
} else {
|
||||
#ifdef CHAT_DEBUG
|
||||
std::cerr << "No avatar for this peer. Requesting it by sending request packet." << std::endl ;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
sendAvatarRequest(peer_id);
|
||||
}
|
||||
|
||||
void p3ChatService::sendAvatarRequest(const std::string& peer_id)
|
||||
|
@ -1543,7 +1606,7 @@ void p3ChatService::sendAvatarRequest(const std::string& peer_id)
|
|||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
sendItem(ci);
|
||||
sendPrivateChatItem(ci);
|
||||
}
|
||||
|
||||
void p3ChatService::sendCustomStateRequest(const std::string& peer_id){
|
||||
|
@ -1559,7 +1622,7 @@ void p3ChatService::sendCustomStateRequest(const std::string& peer_id){
|
|||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
sendItem(cs);
|
||||
sendPrivateChatItem(cs);
|
||||
}
|
||||
|
||||
RsChatStatusItem *p3ChatService::makeOwnCustomStateStringItem()
|
||||
|
@ -1601,7 +1664,7 @@ void p3ChatService::sendAvatarJpegData(const std::string& peer_id)
|
|||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
sendItem(ci) ;
|
||||
sendPrivateChatItem(ci) ;
|
||||
}
|
||||
else {
|
||||
#ifdef CHAT_DEBUG
|
||||
|
@ -1619,7 +1682,7 @@ std::cerr << "p3chatservice: sending requested status string for peer " << peer_
|
|||
RsChatStatusItem *cs = makeOwnCustomStateStringItem();
|
||||
cs->PeerId(peer_id);
|
||||
|
||||
sendItem(cs);
|
||||
sendPrivateChatItem(cs);
|
||||
}
|
||||
|
||||
bool p3ChatService::loadList(std::list<RsItem*>& load)
|
||||
|
@ -1683,6 +1746,24 @@ bool p3ChatService::loadList(std::list<RsItem*>& load)
|
|||
continue;
|
||||
}
|
||||
|
||||
RsPrivateChatDistantInviteConfigItem *ditem = NULL ;
|
||||
|
||||
if(NULL != (ditem = dynamic_cast<RsPrivateChatDistantInviteConfigItem *>(*it)))
|
||||
{
|
||||
DistantChatInvite invite ;
|
||||
|
||||
memcpy(invite.aes_key,ditem->aes_key,DISTANT_CHAT_AES_KEY_SIZE) ;
|
||||
invite.encrypted_radix64_string = ditem->encrypted_radix64_string ;
|
||||
invite.destination_pgp_id = ditem->destination_pgp_id ;
|
||||
invite.time_of_validity = ditem->time_of_validity ;
|
||||
invite.last_hit_time = ditem->last_hit_time ;
|
||||
|
||||
_distant_chat_invites[ditem->hash] = invite ;
|
||||
|
||||
delete *it ;
|
||||
continue ;
|
||||
}
|
||||
|
||||
RsConfigKeyValueSet *vitem = NULL ;
|
||||
|
||||
if(NULL != (vitem = dynamic_cast<RsConfigKeyValueSet*>(*it)))
|
||||
|
@ -1746,6 +1827,21 @@ bool p3ChatService::saveList(bool& cleanup, std::list<RsItem*>& list)
|
|||
list.push_back(ci);
|
||||
}
|
||||
|
||||
/* save ongoing distant chat invites */
|
||||
|
||||
for(std::map<TurtleFileHash,DistantChatInvite>::const_iterator it(_distant_chat_invites.begin());it!=_distant_chat_invites.end();++it)
|
||||
{
|
||||
RsPrivateChatDistantInviteConfigItem *ei = new RsPrivateChatDistantInviteConfigItem ;
|
||||
ei->hash = it->first ;
|
||||
memcpy(ei->aes_key,it->second.aes_key,DISTANT_CHAT_AES_KEY_SIZE) ;
|
||||
ei->encrypted_radix64_string = it->second.encrypted_radix64_string ;
|
||||
ei->destination_pgp_id = it->second.destination_pgp_id ;
|
||||
ei->time_of_validity = it->second.time_of_validity ;
|
||||
ei->last_hit_time = it->second.last_hit_time ;
|
||||
|
||||
list.push_back(ei) ;
|
||||
}
|
||||
|
||||
RsConfigKeyValueSet *vitem = new RsConfigKeyValueSet ;
|
||||
RsTlvKeyValue kv;
|
||||
kv.key = "DEFAULT_NICK_NAME" ;
|
||||
|
@ -1780,10 +1876,14 @@ void p3ChatService::statusChange(const std::list<pqipeer> &plist)
|
|||
for (it = plist.begin(); it != plist.end(); it++) {
|
||||
if (it->state & RS_PEER_S_FRIEND) {
|
||||
if (it->actions & RS_PEER_CONNECTED) {
|
||||
|
||||
/* send the saved outgoing messages */
|
||||
bool changed = false;
|
||||
|
||||
if (privateOutgoingList.size()) {
|
||||
std::vector<RsChatMsgItem*> to_send ;
|
||||
|
||||
if (privateOutgoingList.size())
|
||||
{
|
||||
RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/
|
||||
|
||||
std::string ownId = mLinkMgr->getOwnId();
|
||||
|
@ -1795,7 +1895,7 @@ void p3ChatService::statusChange(const std::list<pqipeer> &plist)
|
|||
if (c->PeerId() == it->id) {
|
||||
mHistoryMgr->addMessage(false, c->PeerId(), ownId, c);
|
||||
|
||||
checkSizeAndSendMessage_deprecated(c); // delete item
|
||||
to_send.push_back(c) ;
|
||||
|
||||
changed = true;
|
||||
|
||||
|
@ -1808,6 +1908,9 @@ void p3ChatService::statusChange(const std::list<pqipeer> &plist)
|
|||
}
|
||||
} /* UNLOCKED */
|
||||
|
||||
for(uint32_t i=0;i<to_send.size();++i)
|
||||
checkSizeAndSendMessage_deprecated(to_send[i]); // delete item
|
||||
|
||||
if (changed) {
|
||||
rsicontrol->getNotify().notifyListChange(NOTIFY_LIST_PRIVATE_OUTGOING_CHAT, NOTIFY_TYPE_DEL);
|
||||
|
||||
|
@ -2745,4 +2848,534 @@ void p3ChatService::cleanLobbyCaches()
|
|||
sendConnectionChallenge(*it) ;
|
||||
}
|
||||
|
||||
bool p3ChatService::handleTunnelRequest(const std::string& hash,const std::string& peer_id)
|
||||
{
|
||||
RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/
|
||||
|
||||
std::map<TurtleFileHash,DistantChatInvite>::iterator it = _distant_chat_invites.find(hash) ;
|
||||
|
||||
#ifdef DEBUG_DISTANT_CHAT
|
||||
std::cerr << "p3ChatService::handleTunnelRequest: received tunnel request for hash " << hash << std::endl;
|
||||
#endif
|
||||
|
||||
if(it == _distant_chat_invites.end())
|
||||
return false ;
|
||||
|
||||
it->second.last_hit_time = time(NULL) ;
|
||||
return true ;
|
||||
}
|
||||
|
||||
void p3ChatService::addVirtualPeer(const TurtleFileHash& hash,const TurtleVirtualPeerId& virtual_peer_id,RsTurtleGenericTunnelItem::Direction dir)
|
||||
{
|
||||
#ifdef DEBUG_DISTANT_CHAT
|
||||
std::cerr << "p3ChatService:: adding new virtual peer " << virtual_peer_id << " for hash " << hash << std::endl;
|
||||
#endif
|
||||
time_t now = time(NULL) ;
|
||||
|
||||
if(dir == RsTurtleGenericTunnelItem::DIRECTION_SERVER)
|
||||
{
|
||||
RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/
|
||||
|
||||
#ifdef DEBUG_DISTANT_CHAT
|
||||
std::cerr << " Side is in direction to server." << std::endl;
|
||||
#endif
|
||||
|
||||
std::map<TurtleFileHash,DistantChatPeerInfo>::iterator it = _distant_chat_peers.find(hash) ;
|
||||
|
||||
if(it == _distant_chat_peers.end())
|
||||
{
|
||||
std::cerr << "(EE) Cannot add virtual peer for hash " << hash << ": no chat invite found for that hash." << std::endl;
|
||||
return ;
|
||||
}
|
||||
|
||||
it->second.last_contact = now ;
|
||||
it->second.status = RS_DISTANT_CHAT_STATUS_TUNNEL_OK ;
|
||||
it->second.virtual_peer_id = virtual_peer_id ;
|
||||
|
||||
#ifdef DEBUG_DISTANT_CHAT
|
||||
std::cerr << "(II) Adding virtual peer " << virtual_peer_id << " for chat hash " << hash << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
if(dir == RsTurtleGenericTunnelItem::DIRECTION_CLIENT)
|
||||
{
|
||||
RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/
|
||||
|
||||
#ifdef DEBUG_DISTANT_CHAT
|
||||
std::cerr << " Side is in direction to client." << std::endl;
|
||||
std::cerr << " Initing encryption parameters from existing distant chat invites." << std::endl;
|
||||
#endif
|
||||
|
||||
std::map<TurtleFileHash,DistantChatInvite>::iterator it = _distant_chat_invites.find(hash) ;
|
||||
|
||||
if(it == _distant_chat_invites.end())
|
||||
{
|
||||
std::cerr << "(EE) Cannot find distant chat invite for hash " << hash << ": no chat invite found for that hash." << std::endl;
|
||||
return ;
|
||||
}
|
||||
DistantChatPeerInfo info ;
|
||||
info.last_contact = now ;
|
||||
info.status = RS_DISTANT_CHAT_STATUS_TUNNEL_OK ;
|
||||
info.virtual_peer_id = virtual_peer_id ;
|
||||
info.pgp_id = it->second.destination_pgp_id ;
|
||||
memcpy(info.aes_key,it->second.aes_key,DISTANT_CHAT_AES_KEY_SIZE) ;
|
||||
|
||||
_distant_chat_peers[hash] = info ;
|
||||
it->second.last_hit_time = now ;
|
||||
}
|
||||
|
||||
rsicontrol->getNotify().notifyChatStatus(hash,"tunnel is up again!",true) ;
|
||||
rsicontrol->getNotify().notifyPeerStatusChanged(hash,RS_STATUS_ONLINE) ;
|
||||
|
||||
getPqiNotify()->AddPopupMessage(RS_POPUP_CHAT, hash, "Distant peer", "Conversation starts...");
|
||||
}
|
||||
|
||||
void p3ChatService::removeVirtualPeer(const TurtleFileHash& hash,const TurtleVirtualPeerId& virtual_peer_id)
|
||||
{
|
||||
{
|
||||
RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/
|
||||
|
||||
std::map<std::string,DistantChatPeerInfo>::iterator it = _distant_chat_peers.find(hash) ;
|
||||
|
||||
if(it == _distant_chat_peers.end())
|
||||
{
|
||||
std::cerr << "(EE) Cannot remove virtual peer " << virtual_peer_id << ": not found in chat list!!" << std::endl;
|
||||
return ;
|
||||
}
|
||||
|
||||
it->second.status = RS_DISTANT_CHAT_STATUS_TUNNEL_DN ;
|
||||
}
|
||||
rsicontrol->getNotify().notifyChatStatus(hash,"tunnel is down...",true) ;
|
||||
rsicontrol->getNotify().notifyPeerStatusChanged(hash,RS_STATUS_OFFLINE) ;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_DISTANT_CHAT
|
||||
static void printBinaryData(void *data,uint32_t size)
|
||||
{
|
||||
static const char outl[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' } ;
|
||||
|
||||
for(uint32_t j = 0; j < size; j++)
|
||||
{
|
||||
std::cerr << outl[ ( ((uint8_t*)data)[j]>>4) ] ;
|
||||
std::cerr << outl[ ((uint8_t*)data)[j] & 0xf ] ;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void p3ChatService::receiveTurtleData( RsTurtleGenericTunnelItem *gitem,const std::string& hash,
|
||||
const std::string& virtual_peer_id,RsTurtleGenericTunnelItem::Direction direction)
|
||||
{
|
||||
#ifdef DEBUG_DISTANT_CHAT
|
||||
std::cerr << "p3ChatService::receiveTurtleData(): Received turtle data. " << std::endl;
|
||||
std::cerr << " hash = " << hash << std::endl;
|
||||
std::cerr << " vpid = " << virtual_peer_id << std::endl;
|
||||
std::cerr << " dir = " << virtual_peer_id << std::endl;
|
||||
#endif
|
||||
|
||||
RsTurtleGenericDataItem *item = dynamic_cast<RsTurtleGenericDataItem*>(gitem) ;
|
||||
|
||||
if(item == NULL)
|
||||
{
|
||||
std::cerr << "(EE) item is not a data item. That is an error." << std::endl;
|
||||
return ;
|
||||
}
|
||||
#ifdef DEBUG_DISTANT_CHAT
|
||||
std::cerr << " size = " << item->data_size << std::endl;
|
||||
std::cerr << " data = " << (void*)item->data_bytes << std::endl;
|
||||
std::cerr << " IV = " << std::hex << *(uint64_t*)item->data_bytes << std::dec << std::endl;
|
||||
std::cerr << " data = " ;
|
||||
|
||||
printBinaryData(item->data_bytes,item->data_size) ;
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
uint8_t aes_key[DISTANT_CHAT_AES_KEY_SIZE] ;
|
||||
|
||||
{
|
||||
RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/
|
||||
std::map<std::string,DistantChatPeerInfo>::iterator it = _distant_chat_peers.find(hash) ;
|
||||
|
||||
if(it == _distant_chat_peers.end())
|
||||
{
|
||||
std::cerr << "(EE) item is not coming out of a registered tunnel. Weird. hash=" << hash << ", peer id = " << virtual_peer_id << std::endl;
|
||||
return ;
|
||||
}
|
||||
it->second.last_contact = time(NULL) ;
|
||||
memcpy(aes_key,it->second.aes_key,DISTANT_CHAT_AES_KEY_SIZE) ;
|
||||
it->second.status = RS_DISTANT_CHAT_STATUS_CAN_TALK ;
|
||||
}
|
||||
|
||||
// Call the AES crypto module
|
||||
// - the IV is the first 8 bytes of item->data_bytes
|
||||
|
||||
if(item->data_size < 8)
|
||||
{
|
||||
std::cerr << "(EE) item encrypted data stream is too small: size = " << item->data_size << std::endl;
|
||||
return ;
|
||||
}
|
||||
uint32_t decrypted_size = RsAES::get_buffer_size(item->data_size-8);
|
||||
uint8_t *decrypted_data = new uint8_t[decrypted_size];
|
||||
|
||||
#ifdef DEBUG_DISTANT_CHAT
|
||||
std::cerr << " Using IV: " << std::hex << *(uint64_t*)item->data_bytes << std::dec << std::endl;
|
||||
std::cerr << " Decrypted buffer size: " << decrypted_size << std::endl;
|
||||
std::cerr << " key : " ; printBinaryData(aes_key,16) ; std::cerr << std::endl;
|
||||
std::cerr << " data : " ; printBinaryData(item->data_bytes,item->data_size) ; std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
if(!RsAES::aes_decrypt_8_16((uint8_t*)item->data_bytes+8,item->data_size-8,aes_key,(uint8_t*)item->data_bytes,decrypted_data,decrypted_size))
|
||||
{
|
||||
std::cerr << "(EE) packet decryption failed." << std::endl;
|
||||
delete[] decrypted_data ;
|
||||
return ;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_DISTANT_CHAT
|
||||
std::cerr << "(II) Decrypted data: size=" << decrypted_size << std::endl;
|
||||
#endif
|
||||
|
||||
// Now try deserialise the decrypted data to make an RsItem out of it.
|
||||
//
|
||||
RsItem *citem = _serializer->deserialise(decrypted_data,&decrypted_size) ;
|
||||
delete[] decrypted_data ;
|
||||
|
||||
if(citem == NULL)
|
||||
{
|
||||
std::cerr << "(EE) item could not be de-serialized. That is an error." << std::endl;
|
||||
return ;
|
||||
}
|
||||
|
||||
// Setup the virtual peer to be the origin, and pass it on.
|
||||
//
|
||||
citem->PeerId(hash) ;
|
||||
handleIncomingItem(citem) ; // Treats the item, and deletes it
|
||||
}
|
||||
|
||||
void p3ChatService::sendTurtleData(RsChatItem *item)
|
||||
{
|
||||
#ifdef DEBUG_DISTANT_CHAT
|
||||
std::cerr << "p3ChatService::sendTurtleData(): try sending item " << (void*)item << " to tunnel " << item->PeerId() << std::endl;
|
||||
#endif
|
||||
|
||||
uint32_t rssize = item->serial_size();
|
||||
uint8_t *buff = new uint8_t[rssize] ;
|
||||
|
||||
if(!item->serialise(buff,rssize))
|
||||
{
|
||||
std::cerr << "(EE) p3ChatService::sendTurtleData(): Could not serialise item!" << std::endl;
|
||||
delete[] buff ;
|
||||
return ;
|
||||
}
|
||||
#ifdef DEBUG_DISTANT_CHAT
|
||||
std::cerr << " Serialized item has size " << rssize << std::endl;
|
||||
#endif
|
||||
|
||||
uint8_t aes_key[DISTANT_CHAT_AES_KEY_SIZE] ;
|
||||
std::string virtual_peer_id ;
|
||||
|
||||
{
|
||||
RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/
|
||||
std::map<std::string,DistantChatPeerInfo>::iterator it = _distant_chat_peers.find(item->PeerId()) ;
|
||||
|
||||
if(it == _distant_chat_peers.end())
|
||||
{
|
||||
std::cerr << "(EE) item is not coming out of a registered tunnel. Weird. peer id = " << virtual_peer_id << std::endl;
|
||||
delete[] buff ;
|
||||
return ;
|
||||
}
|
||||
it->second.last_contact = time(NULL) ;
|
||||
virtual_peer_id = it->second.virtual_peer_id ;
|
||||
memcpy(aes_key,it->second.aes_key,DISTANT_CHAT_AES_KEY_SIZE) ;
|
||||
}
|
||||
#ifdef DEBUG_DISTANT_CHAT
|
||||
std::cerr << "p3ChatService::sendTurtleData(): tunnel found. Encrypting data." << std::endl;
|
||||
#endif
|
||||
|
||||
// Now encrypt this data using AES.
|
||||
//
|
||||
uint8_t *encrypted_data = new uint8_t[RsAES::get_buffer_size(rssize)];
|
||||
uint32_t encrypted_size = RsAES::get_buffer_size(rssize);
|
||||
|
||||
uint64_t IV = RSRandom::random_u64() ; // make a random 8 bytes IV
|
||||
|
||||
#ifdef DEBUG_DISTANT_CHAT
|
||||
std::cerr << " Using IV: " << std::hex << IV << std::dec << std::endl;
|
||||
std::cerr << " Using Key: " ; printBinaryData(aes_key,16) ; std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
if(!RsAES::aes_crypt_8_16(buff,rssize,aes_key,(uint8_t*)&IV,encrypted_data,encrypted_size))
|
||||
{
|
||||
std::cerr << "(EE) packet encryption failed." << std::endl;
|
||||
delete[] encrypted_data ;
|
||||
delete[] buff ;
|
||||
return ;
|
||||
}
|
||||
delete[] buff ;
|
||||
|
||||
// make a TurtleGenericData item out of it:
|
||||
//
|
||||
RsTurtleGenericDataItem *gitem = new RsTurtleGenericDataItem ;
|
||||
|
||||
gitem->data_size = encrypted_size + 8 ;
|
||||
gitem->data_bytes = malloc(gitem->data_size) ;
|
||||
|
||||
memcpy(gitem->data_bytes ,&IV,8) ;
|
||||
memcpy(gitem->data_bytes+8,encrypted_data,encrypted_size) ;
|
||||
|
||||
delete[] encrypted_data ;
|
||||
delete item ;
|
||||
|
||||
#ifdef DEBUG_DISTANT_CHAT
|
||||
std::cerr << "p3ChatService::sendTurtleData(): Sending through virtual peer: " << virtual_peer_id << std::endl;
|
||||
std::cerr << " gitem->data_size = " << gitem->data_size << std::endl;
|
||||
std::cerr << " data = " ;
|
||||
|
||||
printBinaryData(gitem->data_bytes,gitem->data_size) ;
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
mTurtle->sendTurtleData(virtual_peer_id,gitem) ;
|
||||
}
|
||||
|
||||
bool p3ChatService::createDistantChatInvite(const std::string& pgp_id,time_t time_of_validity,std::string& encrypted_radix64_string)
|
||||
{
|
||||
// create the invite
|
||||
|
||||
time_t now = time(NULL) ;
|
||||
|
||||
DistantChatInvite invite ;
|
||||
invite.time_of_validity = now + time_of_validity ;
|
||||
invite.last_hit_time = now ;
|
||||
|
||||
RAND_bytes( (unsigned char *)&invite.aes_key[0],DISTANT_CHAT_AES_KEY_SIZE ) ; // generate a random AES encryption key
|
||||
|
||||
// Create a random hash for that invite.
|
||||
//
|
||||
unsigned char hash_bytes[DISTANT_CHAT_HASH_SIZE] ;
|
||||
RAND_bytes( hash_bytes, DISTANT_CHAT_HASH_SIZE) ;
|
||||
|
||||
std::string hash = t_RsGenericIdType<DISTANT_CHAT_HASH_SIZE>(hash_bytes).toStdString(false) ;
|
||||
|
||||
#ifdef DEBUG_DISTANT_CHAT
|
||||
std::cerr << "Created new distant chat invite: " << std::endl;
|
||||
std::cerr << " validity time stamp = " << invite.time_of_validity << std::endl;
|
||||
std::cerr << " hash = " << hash << std::endl;
|
||||
std::cerr << " encryption key = " ;
|
||||
static const char outl[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' } ;
|
||||
for(uint32_t j = 0; j < 16; j++) { std::cerr << outl[ (invite.aes_key[j]>>4) ] ; std::cerr << outl[ invite.aes_key[j] & 0xf ] ; }
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
// Now encrypt the data to create the link info. We need
|
||||
//
|
||||
// [E] - the hash
|
||||
// [E] - the aes key
|
||||
// [E] - the signature
|
||||
// - pgp id
|
||||
// - timestamp
|
||||
//
|
||||
// The link will be
|
||||
//
|
||||
// retroshare://chat?time_stamp=3243242&private_data=[radix64 string]
|
||||
|
||||
uint32_t header_size = DISTANT_CHAT_AES_KEY_SIZE + DISTANT_CHAT_HASH_SIZE + KEY_ID_SIZE;
|
||||
unsigned char *data = new unsigned char[header_size+400] ;
|
||||
|
||||
PGPIdType OwnId(AuthGPG::getAuthGPG()->getGPGOwnId());
|
||||
|
||||
memcpy(data ,hash_bytes ,DISTANT_CHAT_HASH_SIZE) ;
|
||||
memcpy(data+DISTANT_CHAT_HASH_SIZE ,invite.aes_key ,DISTANT_CHAT_AES_KEY_SIZE) ;
|
||||
memcpy(data+DISTANT_CHAT_HASH_SIZE+DISTANT_CHAT_AES_KEY_SIZE,OwnId.toByteArray(),KEY_ID_SIZE) ;
|
||||
|
||||
#ifdef DEBUG_DISTANT_CHAT
|
||||
std::cerr << "Performing signature " << std::endl;
|
||||
#endif
|
||||
uint32_t signlen = 400;
|
||||
|
||||
if(!AuthGPG::getAuthGPG()->SignDataBin(data,header_size,data+header_size,&signlen))
|
||||
return false ;
|
||||
|
||||
#ifdef DEBUG_DISTANT_CHAT
|
||||
std::cerr << "Signature length = " << signlen << std::endl;
|
||||
#endif
|
||||
|
||||
// Then encrypt the whole data into a single string.
|
||||
|
||||
unsigned char *encrypted_data = new unsigned char[2000] ;
|
||||
uint32_t encrypted_size = 2000 ;
|
||||
|
||||
if(!AuthGPG::getAuthGPG()->encryptDataBin(pgp_id,(unsigned char *)data,signlen+header_size,encrypted_data,&encrypted_size))
|
||||
return false ;
|
||||
|
||||
#ifdef DEBUG_DISTANT_CHAT
|
||||
std::cerr << "Encrypted data size: " << encrypted_size << std::endl;
|
||||
#endif
|
||||
|
||||
Radix64::encode((const char *)encrypted_data,encrypted_size,invite.encrypted_radix64_string) ;
|
||||
invite.destination_pgp_id = pgp_id ;
|
||||
|
||||
{
|
||||
RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/
|
||||
_distant_chat_invites[hash] = invite ;
|
||||
}
|
||||
|
||||
encrypted_radix64_string = invite.encrypted_radix64_string ;
|
||||
#ifdef DEBUG_DISTANT_CHAT
|
||||
std::cerr << "Encrypted radix64 string: " << invite.encrypted_radix64_string << std::endl;
|
||||
#endif
|
||||
|
||||
IndicateConfigChanged();
|
||||
return true ;
|
||||
}
|
||||
|
||||
bool p3ChatService::initiateDistantChatConnexion(const std::string& encrypted_str,std::string& hash,uint32_t& error_code)
|
||||
{
|
||||
RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/
|
||||
|
||||
// Un-radix the string.
|
||||
//
|
||||
char *encrypted_data_bin = NULL ;
|
||||
size_t encrypted_data_len ;
|
||||
|
||||
Radix64::decode(encrypted_str,encrypted_data_bin,encrypted_data_len) ;
|
||||
|
||||
// Decrypt it.
|
||||
//
|
||||
uint32_t data_size = encrypted_data_len+1000;
|
||||
unsigned char *data = new unsigned char[data_size] ;
|
||||
|
||||
if(!AuthGPG::getAuthGPG()->decryptDataBin((unsigned char *)encrypted_data_bin,encrypted_data_len,data,&data_size))
|
||||
{
|
||||
error_code = RS_DISTANT_CHAT_ERROR_DECRYPTION_FAILED ;
|
||||
return false ;
|
||||
}
|
||||
delete[] encrypted_data_bin ;
|
||||
|
||||
#ifdef DEBUG_DISTANT_CHAT
|
||||
std::cerr << "Chat invite was successfuly decrypted!" << std::endl;
|
||||
#endif
|
||||
|
||||
uint32_t header_size = DISTANT_CHAT_HASH_SIZE + DISTANT_CHAT_AES_KEY_SIZE + KEY_ID_SIZE ;
|
||||
|
||||
PGPIdType pgp_id( data + DISTANT_CHAT_HASH_SIZE + DISTANT_CHAT_AES_KEY_SIZE ) ;
|
||||
|
||||
#ifdef DEBUG_DISTANT_CHAT
|
||||
std::cerr << "Got this PGP id: " << pgp_id.toStdString() << std::endl;
|
||||
#endif
|
||||
|
||||
PGPFingerprintType fingerprint ;
|
||||
if(!AuthGPG::getAuthGPG()->getKeyFingerprint(pgp_id,fingerprint))
|
||||
{
|
||||
error_code = RS_DISTANT_CHAT_ERROR_UNKNOWN_KEY ;
|
||||
return false ;
|
||||
}
|
||||
|
||||
if(!AuthGPG::getAuthGPG()->VerifySignBin(data,header_size,data+header_size,data_size-header_size,fingerprint.toStdString()))
|
||||
{
|
||||
error_code = RS_DISTANT_CHAT_ERROR_SIGNATURE_MISMATCH ;
|
||||
return false ;
|
||||
}
|
||||
#ifdef DEBUG_DISTANT_CHAT
|
||||
std::cerr << "Signature successfuly verified!" << std::endl;
|
||||
#endif
|
||||
|
||||
hash = t_RsGenericIdType<DISTANT_CHAT_HASH_SIZE>(data).toStdString(false) ;
|
||||
DistantChatPeerInfo info ;
|
||||
|
||||
info.last_contact = time(NULL) ;
|
||||
info.status = RS_DISTANT_CHAT_STATUS_TUNNEL_DN ;
|
||||
info.pgp_id = pgp_id.toStdString() ;
|
||||
memcpy(info.aes_key,data+DISTANT_CHAT_HASH_SIZE,DISTANT_CHAT_AES_KEY_SIZE) ;
|
||||
|
||||
_distant_chat_peers[hash] = info ;
|
||||
|
||||
delete[] data ;
|
||||
|
||||
// Now ask the turtle router to manage a tunnel for that hash.
|
||||
|
||||
#ifdef DEBUG_DISTANT_CHAT
|
||||
std::cerr << "Asking turtle router to monitor tunnels for hash " << hash << std::endl;
|
||||
#endif
|
||||
|
||||
mTurtle->monitorTunnels(hash,this) ;
|
||||
|
||||
// And notify about chatting.
|
||||
|
||||
error_code = RS_DISTANT_CHAT_ERROR_NO_ERROR ;
|
||||
return true ;
|
||||
}
|
||||
|
||||
void p3ChatService::cleanDistantChatInvites()
|
||||
{
|
||||
RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/
|
||||
|
||||
time_t now = time(NULL) ;
|
||||
|
||||
#ifdef DEBUG_DISTANT_CHAT
|
||||
std::cerr << "p3ChatService::cleanDistantChatInvites: " << std::endl;
|
||||
#endif
|
||||
|
||||
for(std::map<TurtleFileHash,DistantChatInvite>::iterator it(_distant_chat_invites.begin());it!=_distant_chat_invites.end(); )
|
||||
if(it->second.time_of_validity < now)
|
||||
{
|
||||
#ifdef DEBUG_DISTANT_CHAT
|
||||
std::cerr << " Removing hash " << it->first << std::endl;
|
||||
#endif
|
||||
std::map<TurtleFileHash,DistantChatInvite>::iterator tmp(it) ;
|
||||
++it ;
|
||||
_distant_chat_invites.erase(tmp) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef DEBUG_DISTANT_CHAT
|
||||
std::cerr << " Keeping hash " << it->first << std::endl;
|
||||
#endif
|
||||
++it ;
|
||||
}
|
||||
}
|
||||
|
||||
bool p3ChatService::getDistantChatInviteList(std::vector<DistantChatInviteInfo>& invites)
|
||||
{
|
||||
invites.clear() ;
|
||||
|
||||
RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/
|
||||
for(std::map<std::string,DistantChatInvite>::const_iterator it(_distant_chat_invites.begin());it!=_distant_chat_invites.end();++it)
|
||||
{
|
||||
DistantChatInviteInfo info ;
|
||||
info.hash = it->first ;
|
||||
info.encrypted_radix64_string = it->second.encrypted_radix64_string ;
|
||||
info.time_of_validity = it->second.time_of_validity ;
|
||||
info.destination_pgp_id = it->second.destination_pgp_id ;
|
||||
|
||||
invites.push_back(info);
|
||||
}
|
||||
return true ;
|
||||
}
|
||||
|
||||
bool p3ChatService::getDistantChatStatus(const std::string& hash,uint32_t& status,std::string& pgp_id)
|
||||
{
|
||||
RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/
|
||||
|
||||
std::map<TurtleFileHash,DistantChatPeerInfo>::const_iterator it = _distant_chat_peers.find(hash) ;
|
||||
|
||||
if(it == _distant_chat_peers.end())
|
||||
return false ;
|
||||
|
||||
status = it->second.status ;
|
||||
pgp_id = it->second.pgp_id ;
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -33,10 +33,13 @@
|
|||
|
||||
#include "serialiser/rsmsgitems.h"
|
||||
#include "services/p3service.h"
|
||||
#include "pgp/pgphandler.h"
|
||||
#include "turtle/turtleclientservice.h"
|
||||
#include "retroshare/rsmsgs.h"
|
||||
|
||||
class p3LinkMgr;
|
||||
class p3HistoryMgr;
|
||||
class p3turtle ;
|
||||
|
||||
//!The basic Chat service.
|
||||
/**
|
||||
|
@ -45,7 +48,7 @@ class p3HistoryMgr;
|
|||
* This service uses rsnotify (callbacks librs clients (e.g. rs-gui))
|
||||
* @see NotifyBase
|
||||
*/
|
||||
class p3ChatService: public p3Service, public p3Config, public pqiMonitor
|
||||
class p3ChatService: public p3Service, public p3Config, public pqiMonitor, public RsTurtleClientService
|
||||
{
|
||||
public:
|
||||
p3ChatService(p3LinkMgr *cm, p3HistoryMgr *historyMgr);
|
||||
|
@ -183,6 +186,7 @@ class p3ChatService: public p3Service, public p3Config, public pqiMonitor
|
|||
virtual void saveDone();
|
||||
virtual bool loadList(std::list<RsItem*>& load) ;
|
||||
|
||||
bool isOnline(const std::string& id) ;
|
||||
private:
|
||||
RsMutex mChatMtx;
|
||||
|
||||
|
@ -191,6 +195,7 @@ class p3ChatService: public p3Service, public p3Config, public pqiMonitor
|
|||
|
||||
// Receive chat queue
|
||||
void receiveChatQueue();
|
||||
void handleIncomingItem(RsItem *); // called by the former, and turtle handler for incoming encrypted items
|
||||
|
||||
void initRsChatInfo(RsChatMsgItem *c, ChatInfo &i);
|
||||
|
||||
|
@ -289,9 +294,69 @@ class p3ChatService: public p3Service, public p3Config, public pqiMonitor
|
|||
std::map<std::string,ChatLobbyId> _lobby_ids ;
|
||||
std::string _default_nick_name ;
|
||||
float _time_shift_average ;
|
||||
time_t last_lobby_challenge_time ; // prevents bruteforce attack
|
||||
time_t last_lobby_challenge_time ; // prevents bruteforce attack
|
||||
time_t last_visible_lobby_info_request_time ; // allows to ask for updates
|
||||
bool _should_reset_lobby_counts ;
|
||||
|
||||
RsChatSerialiser *_serializer ;
|
||||
|
||||
// ===========================================================//
|
||||
// Members related to anonymous distant chat. //
|
||||
// ===========================================================//
|
||||
|
||||
public:
|
||||
void connectToTurtleRouter(p3turtle *) ;
|
||||
|
||||
// Creates the invite if the public key of the distant peer is available.
|
||||
// Om success, stores the invite in the map above, so that we can respond to tunnel requests.
|
||||
//
|
||||
bool createDistantChatInvite(const std::string& pgp_id,time_t time_of_validity,TurtleFileHash& hash) ;
|
||||
bool getDistantChatInviteList(std::vector<DistantChatInviteInfo>& invites) ;
|
||||
bool initiateDistantChatConnexion(const std::string& encrypted_string,std::string& hash,uint32_t& error_code) ;
|
||||
|
||||
virtual bool getDistantChatStatus(const std::string& hash,uint32_t& status,std::string& pgp_id) ;
|
||||
|
||||
private:
|
||||
struct DistantChatInvite
|
||||
{
|
||||
unsigned char aes_key[16] ;
|
||||
std::string encrypted_radix64_string ;
|
||||
std::string destination_pgp_id ;
|
||||
time_t time_of_validity ;
|
||||
time_t last_hit_time ;
|
||||
};
|
||||
struct DistantChatPeerInfo
|
||||
{
|
||||
time_t last_contact ; // used to send keep alive packets
|
||||
unsigned char aes_key[16] ; // key to encrypt packets
|
||||
uint32_t status ; // info: do we have a tunnel ?
|
||||
std::string virtual_peer_id; // given by the turtle router. Identifies the tunnel.
|
||||
std::string pgp_id ; // pgp id of the peer we're talking to.
|
||||
};
|
||||
|
||||
// This map contains the ongoing invites. This is the list where to look to
|
||||
// handle tunnel requests.
|
||||
//
|
||||
std::map<TurtleFileHash,DistantChatInvite> _distant_chat_invites ;
|
||||
|
||||
// This maps contains the current peers to talk to with distant chat.
|
||||
//
|
||||
std::map<std::string,DistantChatPeerInfo> _distant_chat_peers ;
|
||||
|
||||
// Overloaded from RsTurtleClientService
|
||||
|
||||
virtual bool handleTunnelRequest(const std::string& hash,const std::string& peer_id) ;
|
||||
virtual void receiveTurtleData(RsTurtleGenericTunnelItem *item,const std::string& hash,const std::string& virtual_peer_id,RsTurtleGenericTunnelItem::Direction direction) ;
|
||||
void addVirtualPeer(const TurtleFileHash&, const TurtleVirtualPeerId&,RsTurtleGenericTunnelItem::Direction dir) ;
|
||||
void removeVirtualPeer(const TurtleFileHash&, const TurtleVirtualPeerId&) ;
|
||||
|
||||
// Utility functions
|
||||
|
||||
void cleanDistantChatInvites() ;
|
||||
void sendTurtleData(RsChatItem *) ;
|
||||
void sendPrivateChatItem(RsChatItem *) ;
|
||||
|
||||
p3turtle *mTurtle ;
|
||||
};
|
||||
|
||||
class p3ChatService::StateStringInfo
|
||||
|
|
|
@ -25,23 +25,34 @@
|
|||
|
||||
|
||||
#include "retroshare/rsiface.h"
|
||||
#include "retroshare/rspeers.h"
|
||||
|
||||
#include "pqi/pqibin.h"
|
||||
#include "pqi/pqiarchive.h"
|
||||
#include "pqi/p3linkmgr.h"
|
||||
#include "pqi/authgpg.h"
|
||||
|
||||
#include "services/p3msgservice.h"
|
||||
#include "pgp/pgpkeyutil.h"
|
||||
#include "pqi/pqinotify.h"
|
||||
|
||||
#include "util/rsdebug.h"
|
||||
#include "util/rsdir.h"
|
||||
#include "util/rsstring.h"
|
||||
#include "util/radix64.h"
|
||||
#include "util/rsrandom.h"
|
||||
|
||||
#include <iomanip>
|
||||
#include <map>
|
||||
|
||||
//#define DEBUG_DISTANT_MSG
|
||||
|
||||
const int msgservicezone = 54319;
|
||||
|
||||
static const uint32_t RS_DISTANT_MSG_STATUS_TUNNEL_OK = 0x0001 ;
|
||||
static const uint32_t RS_DISTANT_MSG_STATUS_TUNNEL_DN = 0x0000 ;
|
||||
static const uint32_t DISTANT_MSG_HASH_SIZE = 20 ;
|
||||
|
||||
/* Another little hack ..... unique message Ids
|
||||
* will be handled in this class.....
|
||||
* These are unique within this run of the server,
|
||||
|
@ -58,7 +69,8 @@ p3MsgService::p3MsgService(p3LinkMgr *lm)
|
|||
:p3Service(RS_SERVICE_TYPE_MSG), p3Config(CONFIG_TYPE_MSGS),
|
||||
mLinkMgr(lm), mMsgMtx("p3MsgService"), mMsgUniqueId(time(NULL))
|
||||
{
|
||||
addSerialType(new RsMsgSerialiser());
|
||||
_serialiser = new RsMsgSerialiser();
|
||||
addSerialType(_serialiser);
|
||||
|
||||
/* Initialize standard tag types */
|
||||
if(lm)
|
||||
|
@ -81,6 +93,15 @@ int p3MsgService::tick()
|
|||
*/
|
||||
|
||||
incomingMsgs();
|
||||
|
||||
static time_t last_management_time = 0 ;
|
||||
time_t now = time(NULL) ;
|
||||
|
||||
if(now > last_management_time + 5)
|
||||
{
|
||||
manageDistantPeers() ;
|
||||
last_management_time = now ;
|
||||
}
|
||||
//checkOutgoingMessages();
|
||||
|
||||
return 0;
|
||||
|
@ -107,7 +128,7 @@ void p3MsgService::processMsg(RsMsgItem *mi, bool incoming)
|
|||
{
|
||||
/* from a peer */
|
||||
|
||||
mi->msgFlags &= RS_MSG_FLAGS_SYSTEM; // remove flags
|
||||
mi->msgFlags &= (RS_MSG_FLAGS_ENCRYPTED | RS_MSG_FLAGS_SYSTEM); // remove flags except those
|
||||
mi->msgFlags |= RS_MSG_FLAGS_NEW;
|
||||
|
||||
pqiNotify *notify = getPqiNotify();
|
||||
|
@ -187,22 +208,27 @@ int p3MsgService::incomingMsgs()
|
|||
{
|
||||
RsMsgItem *mi;
|
||||
int i = 0;
|
||||
bool changed = false ;
|
||||
|
||||
while((mi = (RsMsgItem *) recvItem()) != NULL)
|
||||
{
|
||||
changed = true ;
|
||||
++i;
|
||||
handleIncomingItem(mi) ;
|
||||
++i ;
|
||||
}
|
||||
|
||||
if(checkAndRebuildPartialMessage(mi)) // only returns true when a msg is complete.
|
||||
{
|
||||
processMsg(mi, true);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
void p3MsgService::handleIncomingItem(RsMsgItem *mi)
|
||||
{
|
||||
bool changed = false ;
|
||||
|
||||
if(checkAndRebuildPartialMessage(mi)) // only returns true when a msg is complete.
|
||||
{
|
||||
processMsg(mi, true);
|
||||
changed = true ;
|
||||
}
|
||||
if(changed)
|
||||
rsicontrol->getNotify().notifyListChange(NOTIFY_LIST_MESSAGELIST,NOTIFY_TYPE_MOD);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void p3MsgService::statusChange(const std::list<pqipeer> &/*plist*/)
|
||||
|
@ -233,10 +259,18 @@ void p3MsgService::checkSizeAndSendMessage(RsMsgItem *msg)
|
|||
// Indicate that the message is to be continued.
|
||||
//
|
||||
item->msgFlags |= RS_MSG_FLAGS_PARTIAL ;
|
||||
sendItem(item) ;
|
||||
|
||||
if(msg->msgFlags & RS_MSG_FLAGS_DISTANT)
|
||||
sendPrivateMsgItem(msg) ;
|
||||
else
|
||||
sendItem(item) ;
|
||||
}
|
||||
std::cerr << " Chopped off msg of size " << msg->message.size() << std::endl;
|
||||
sendItem(msg) ;
|
||||
|
||||
if(msg->msgFlags & RS_MSG_FLAGS_DISTANT)
|
||||
sendPrivateMsgItem(msg) ;
|
||||
else
|
||||
sendItem(msg) ;
|
||||
}
|
||||
|
||||
int p3MsgService::checkOutgoingMessages()
|
||||
|
@ -247,6 +281,7 @@ int p3MsgService::checkOutgoingMessages()
|
|||
*/
|
||||
|
||||
bool changed = false ;
|
||||
std::list<RsMsgItem*> output_queue ;
|
||||
|
||||
{
|
||||
const std::string ownId = mLinkMgr->getOwnId();
|
||||
|
@ -264,18 +299,8 @@ int p3MsgService::checkOutgoingMessages()
|
|||
|
||||
/* find the certificate */
|
||||
std::string pid = mit->second->PeerId();
|
||||
bool toSend = false;
|
||||
|
||||
if (mLinkMgr->isOnline(pid))
|
||||
{
|
||||
toSend = true;
|
||||
}
|
||||
else if (pid == ownId) /* FEEDBACK Msg to Ourselves */
|
||||
{
|
||||
toSend = true;
|
||||
}
|
||||
|
||||
if (toSend)
|
||||
if(mit->second->msgFlags & RS_MSG_FLAGS_DISTANT || mLinkMgr->isOnline(pid) || pid == ownId) /* FEEDBACK Msg to Ourselves */
|
||||
{
|
||||
/* send msg */
|
||||
pqioutput(PQL_DEBUG_BASIC, msgservicezone,
|
||||
|
@ -283,7 +308,7 @@ int p3MsgService::checkOutgoingMessages()
|
|||
/* remove the pending flag */
|
||||
(mit->second)->msgFlags &= ~RS_MSG_FLAGS_PENDING;
|
||||
|
||||
checkSizeAndSendMessage(mit->second) ;
|
||||
output_queue.push_back(mit->second) ;
|
||||
toErase.push_back(mit->first);
|
||||
|
||||
changed = true ;
|
||||
|
@ -317,6 +342,9 @@ int p3MsgService::checkOutgoingMessages()
|
|||
}
|
||||
}
|
||||
|
||||
for(std::list<RsMsgItem*>::const_iterator it(output_queue.begin());it!=output_queue.end();++it)
|
||||
checkSizeAndSendMessage(*it) ;
|
||||
|
||||
if(changed)
|
||||
rsicontrol->getNotify().notifyListChange(NOTIFY_LIST_MESSAGELIST,NOTIFY_TYPE_MOD);
|
||||
|
||||
|
@ -357,6 +385,14 @@ bool p3MsgService::saveList(bool& cleanup, std::list<RsItem*>& itemList)
|
|||
for(mit4 = mParentId.begin(); mit4 != mParentId.end(); mit4++)
|
||||
itemList.push_back(mit4->second);
|
||||
|
||||
for(std::map<std::string,DistantMessengingInvite>::const_iterator it(_messenging_invites.begin());it!=_messenging_invites.end();++it)
|
||||
{
|
||||
RsPublicMsgInviteConfigItem *item = new RsPublicMsgInviteConfigItem ;
|
||||
item->hash = it->first ;
|
||||
item->time_stamp = it->second.time_of_validity ;
|
||||
|
||||
itemList.push_back(item) ;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -421,6 +457,7 @@ bool p3MsgService::loadList(std::list<RsItem*>& load)
|
|||
RsMsgTags* mti;
|
||||
RsMsgSrcId* msi;
|
||||
RsMsgParentId* msp;
|
||||
RsPublicMsgInviteConfigItem* msv;
|
||||
|
||||
std::list<RsMsgItem*> items;
|
||||
std::list<RsItem*>::iterator it;
|
||||
|
@ -442,18 +479,18 @@ bool p3MsgService::loadList(std::list<RsItem*>& load)
|
|||
items.push_back(mitem);
|
||||
}
|
||||
else if(NULL != (mtt = dynamic_cast<RsMsgTagType *>(*it)))
|
||||
{
|
||||
// delete standard tags as they are now save in config
|
||||
if(mTags.end() == (tagIt = mTags.find(mtt->tagId)))
|
||||
{
|
||||
mTags.insert(std::pair<uint32_t, RsMsgTagType* >(mtt->tagId, mtt));
|
||||
}
|
||||
else
|
||||
{
|
||||
delete mTags[mtt->tagId];
|
||||
mTags.erase(tagIt);
|
||||
mTags.insert(std::pair<uint32_t, RsMsgTagType* >(mtt->tagId, mtt));
|
||||
}
|
||||
{
|
||||
// delete standard tags as they are now save in config
|
||||
if(mTags.end() == (tagIt = mTags.find(mtt->tagId)))
|
||||
{
|
||||
mTags.insert(std::pair<uint32_t, RsMsgTagType* >(mtt->tagId, mtt));
|
||||
}
|
||||
else
|
||||
{
|
||||
delete mTags[mtt->tagId];
|
||||
mTags.erase(tagIt);
|
||||
mTags.insert(std::pair<uint32_t, RsMsgTagType* >(mtt->tagId, mtt));
|
||||
}
|
||||
|
||||
}
|
||||
else if(NULL != (mti = dynamic_cast<RsMsgTags *>(*it)))
|
||||
|
@ -469,6 +506,10 @@ bool p3MsgService::loadList(std::list<RsItem*>& load)
|
|||
{
|
||||
mParentId.insert(std::pair<uint32_t, RsMsgParentId*>(msp->msgId, msp));
|
||||
}
|
||||
else if(NULL != (msv = dynamic_cast<RsPublicMsgInviteConfigItem *>(*it)))
|
||||
{
|
||||
_messenging_invites[msv->hash].time_of_validity = msv->time_stamp ;
|
||||
}
|
||||
}
|
||||
|
||||
// sort items into lists
|
||||
|
@ -1357,6 +1398,10 @@ void p3MsgService::initRsMI(RsMsgItem *msg, MessageInfo &mi)
|
|||
{
|
||||
mi.msgflags |= RS_MSG_NEW;
|
||||
}
|
||||
|
||||
if (msg->msgFlags & RS_MSG_FLAGS_ENCRYPTED)
|
||||
mi.msgflags |= RS_MSG_ENCRYPTED ;
|
||||
|
||||
if (msg->msgFlags & RS_MSG_FLAGS_TRASH)
|
||||
{
|
||||
mi.msgflags |= RS_MSG_TRASH;
|
||||
|
@ -1442,6 +1487,9 @@ void p3MsgService::initRsMIS(RsMsgItem *msg, MsgInfoSummary &mis)
|
|||
{
|
||||
mis.msgflags = 0;
|
||||
|
||||
if (msg->msgFlags & RS_MSG_FLAGS_ENCRYPTED)
|
||||
mis.msgflags |= RS_MSG_ENCRYPTED ;
|
||||
|
||||
/* translate flags, if we sent it... outgoing */
|
||||
if ((msg->msgFlags & RS_MSG_FLAGS_OUTGOING)
|
||||
/*|| (msg->PeerId() == mLinkMgr->getOwnId())*/)
|
||||
|
@ -1513,7 +1561,8 @@ RsMsgItem *p3MsgService::initMIRsMsg(MessageInfo &info, const std::string &to)
|
|||
msg -> recvTime = 0;
|
||||
|
||||
msg -> subject = info.title;
|
||||
msg -> message = info.msg;
|
||||
|
||||
msg -> message = info.msg;
|
||||
|
||||
std::list<std::string>::iterator pit;
|
||||
for(pit = info.msgto.begin(); pit != info.msgto.end(); pit++)
|
||||
|
@ -1538,6 +1587,10 @@ RsMsgItem *p3MsgService::initMIRsMsg(MessageInfo &info, const std::string &to)
|
|||
msg -> attachment.title = info.attach_title;
|
||||
msg -> attachment.comment = info.attach_comment;
|
||||
|
||||
RsPeerDetails details ;
|
||||
if(!rsPeers->getPeerDetails(to,details))
|
||||
msg->msgFlags |= RS_MSG_FLAGS_DISTANT;
|
||||
|
||||
std::list<FileInfo>::iterator it;
|
||||
for(it = info.files.begin(); it != info.files.end(); it++)
|
||||
{
|
||||
|
@ -1550,15 +1603,428 @@ RsMsgItem *p3MsgService::initMIRsMsg(MessageInfo &info, const std::string &to)
|
|||
|
||||
/* translate flags from outside */
|
||||
if (info.msgflags & RS_MSG_USER_REQUEST)
|
||||
{
|
||||
msg->msgFlags |= RS_MSG_FLAGS_USER_REQUEST;
|
||||
}
|
||||
if (info.msgflags & RS_MSG_FRIEND_RECOMMENDATION)
|
||||
{
|
||||
msg->msgFlags |= RS_MSG_FLAGS_FRIEND_RECOMMENDATION;
|
||||
}
|
||||
|
||||
//std::cerr << "p3MsgService::initMIRsMsg()" << std::endl;
|
||||
if (info.msgflags & RS_MSG_FRIEND_RECOMMENDATION)
|
||||
msg->msgFlags |= RS_MSG_FLAGS_FRIEND_RECOMMENDATION;
|
||||
|
||||
// See if we need to encrypt this message. If so, we replace the msg text
|
||||
// by the whole message serialized and binary encrypted, so as to obfuscate
|
||||
// all its content.
|
||||
//
|
||||
bool enc_ok = false ;
|
||||
|
||||
if(info.encryption_keys.find(to) != info.encryption_keys.end())
|
||||
encryptMessage(info.encryption_keys[to],msg) ;
|
||||
|
||||
//std::cerr << "p3MsgService::initMIRsMsg()" << std::endl;
|
||||
//msg->print(std::cerr);
|
||||
return msg;
|
||||
}
|
||||
|
||||
bool p3MsgService::encryptMessage(const std::string& pgp_id,RsMsgItem *item)
|
||||
{
|
||||
#ifdef DEBUG_DISTANT_MSG
|
||||
std::cerr << "Encrypting message with public key " << pgp_id << " in place." << std::endl;
|
||||
#endif
|
||||
|
||||
// 1 - serialise the whole message item into a binary chunk.
|
||||
//
|
||||
uint32_t rssize = _serialiser->size(item) ;
|
||||
unsigned char *data = new unsigned char[rssize] ;
|
||||
|
||||
if(!_serialiser->serialise(item,data,&rssize))
|
||||
{
|
||||
std::cerr << "(EE) p3MsgService::sendTurtleData(): Serialization error." << std::endl;
|
||||
delete[] data ;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2 - pgp-encrypt the chunk with the user-supplied public key.
|
||||
//
|
||||
uint32_t encrypted_size = rssize + 1000 ;
|
||||
unsigned char *encrypted_data = new unsigned char[encrypted_size] ;
|
||||
|
||||
if(!AuthGPG::getAuthGPG()->encryptDataBin(pgp_id,data,rssize,encrypted_data,&encrypted_size))
|
||||
{
|
||||
delete[] data ;
|
||||
delete[] encrypted_data ;
|
||||
std::cerr << "Encryption failed!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
delete[] data ;
|
||||
|
||||
// Now turn the binary encrypted chunk into a readable radix string.
|
||||
//
|
||||
std::string armoured_data ;
|
||||
Radix64::encode((char *)encrypted_data,encrypted_size,armoured_data) ;
|
||||
delete[] encrypted_data ;
|
||||
|
||||
std::wstring encrypted_msg ;
|
||||
|
||||
if(!librs::util::ConvertUtf8ToUtf16(armoured_data,encrypted_msg))
|
||||
return false;
|
||||
|
||||
// wipe the item clean and replace the message by the encrypted data.
|
||||
|
||||
item->message = encrypted_msg ;
|
||||
item->subject = L"" ;
|
||||
item->msgcc.ids.clear() ;
|
||||
item->msgbcc.ids.clear() ;
|
||||
item->msgto.ids.clear() ;
|
||||
item->msgFlags |= RS_MSG_FLAGS_ENCRYPTED ;
|
||||
item->attachment.TlvClear() ;
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
bool p3MsgService::decryptMessage(const std::string& mId)
|
||||
{
|
||||
uint32_t msgId = atoi(mId.c_str());
|
||||
std::string encrypted_string ;
|
||||
|
||||
{
|
||||
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
|
||||
|
||||
std::map<uint32_t, RsMsgItem *>::iterator mit = imsg.find(msgId);
|
||||
|
||||
if(mit == imsg.end() || !librs::util::ConvertUtf16ToUtf8(mit->second->message,encrypted_string))
|
||||
return false;
|
||||
}
|
||||
|
||||
char *encrypted_data ;
|
||||
size_t encrypted_size ;
|
||||
|
||||
Radix64::decode(encrypted_string,encrypted_data,encrypted_size) ;
|
||||
|
||||
uint32_t decrypted_size = encrypted_size + 500 ;
|
||||
unsigned char *decrypted_data = new unsigned char[decrypted_size] ;
|
||||
|
||||
if(!AuthGPG::getAuthGPG()->decryptDataBin(encrypted_data,encrypted_size,decrypted_data,&decrypted_size))
|
||||
{
|
||||
delete[] encrypted_data ;
|
||||
delete[] decrypted_data ;
|
||||
std::cerr << "decryption failed!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
RsMsgItem *item = dynamic_cast<RsMsgItem*>(_serialiser->deserialise(decrypted_data,&decrypted_size)) ;
|
||||
|
||||
if(item == NULL)
|
||||
return false ;
|
||||
|
||||
{
|
||||
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
|
||||
*imsg[msgId] = *item ;
|
||||
}
|
||||
delete item ;
|
||||
|
||||
IndicateConfigChanged() ;
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
void p3MsgService::connectToTurtleRouter(p3turtle *pt)
|
||||
{
|
||||
mTurtle = pt ;
|
||||
pt->registerTunnelService(this) ;
|
||||
}
|
||||
bool p3MsgService::createDistantOfflineMessengingInvite(time_t time_of_validity,TurtleFileHash& hash)
|
||||
{
|
||||
unsigned char hash_bytes[DISTANT_MSG_HASH_SIZE] ;
|
||||
RSRandom::random_bytes( hash_bytes, DISTANT_MSG_HASH_SIZE) ;
|
||||
|
||||
hash = t_RsGenericIdType<DISTANT_MSG_HASH_SIZE>(hash_bytes).toStdString(false) ;
|
||||
|
||||
DistantMessengingInvite invite ;
|
||||
invite.time_of_validity = time_of_validity + time(NULL);
|
||||
|
||||
{
|
||||
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
|
||||
_messenging_invites[hash] = invite ;
|
||||
}
|
||||
IndicateConfigChanged() ;
|
||||
|
||||
return true ;
|
||||
}
|
||||
bool p3MsgService::getDistantOfflineMessengingInvites(std::vector<DistantOfflineMessengingInvite>& invites)
|
||||
{
|
||||
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
|
||||
|
||||
for(std::map<std::string,DistantMessengingInvite>::const_iterator it(_messenging_invites.begin());it!=_messenging_invites.end();++it)
|
||||
{
|
||||
DistantOfflineMessengingInvite invite ;
|
||||
invite.hash = it->first ;
|
||||
invite.issuer_pgp_id = AuthGPG::getAuthGPG()->getGPGOwnId() ;
|
||||
invite.time_of_validity = it->second.time_of_validity ;
|
||||
|
||||
invites.push_back(invite) ;
|
||||
|
||||
#ifdef DEBUG_DISTANT_MSG
|
||||
std::cerr << " adding invite with hash " << invite.hash << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
return true ;
|
||||
}
|
||||
bool p3MsgService::handleTunnelRequest(const std::string& hash,const std::string& peer_id)
|
||||
{
|
||||
#ifdef DEBUG_DISTANT_MSG
|
||||
std::cerr << "p3MsgService::handleTunnelRequest: received TR for hash " << hash << std::endl;
|
||||
#endif
|
||||
|
||||
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
|
||||
std::map<std::string,DistantMessengingInvite>::const_iterator it = _messenging_invites.find(hash) ;
|
||||
|
||||
#ifdef DEBUG_DISTANT_MSG
|
||||
if(it != _messenging_invites.end())
|
||||
std::cerr << "Responding OK!" << std::endl;
|
||||
#endif
|
||||
|
||||
return it != _messenging_invites.end() ;
|
||||
}
|
||||
|
||||
void p3MsgService::manageDistantPeers()
|
||||
{
|
||||
// now possibly flush pending messages
|
||||
|
||||
#ifdef DEBUG_DISTANT_MSG
|
||||
std::cerr << "p3MsgService::manageDistantPeers()" << std::endl;
|
||||
#endif
|
||||
|
||||
std::vector<std::pair<std::string,RsMsgItem*> > to_send ;
|
||||
|
||||
{
|
||||
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
|
||||
for(std::map<std::string,DistantMessengingContact>::iterator it(_messenging_contacts.begin());it!=_messenging_contacts.end();++it)
|
||||
if(it->second.status == RS_DISTANT_MSG_STATUS_TUNNEL_OK)
|
||||
{
|
||||
for(uint32_t i=0;i<it->second.pending_messages.size();++i)
|
||||
to_send.push_back(std::pair<std::string,RsMsgItem*>(it->first,it->second.pending_messages[i])) ;
|
||||
|
||||
it->second.pending_messages.clear() ;
|
||||
}
|
||||
}
|
||||
|
||||
for(uint32_t i=0;i<to_send.size();++i)
|
||||
{
|
||||
#ifdef DEBUG_DISTANT_MSG
|
||||
std::cerr << " Flushing msg " << to_send[i].second->msgId << std::endl;
|
||||
#endif
|
||||
sendTurtleData(to_send[i].first,to_send[i].second) ;
|
||||
}
|
||||
|
||||
time_t now = time(NULL) ;
|
||||
{
|
||||
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
|
||||
|
||||
// clean dead invites.
|
||||
//
|
||||
for(std::map<std::string,DistantMessengingInvite>::iterator it(_messenging_invites.begin());it!=_messenging_invites.end();)
|
||||
if(it->second.time_of_validity < now)
|
||||
{
|
||||
#ifdef DEBUG_DISTANT_MSG
|
||||
std::cerr << " Removing outdated invite " << it->second.time_of_validity << ", hash=" << it->first << std::endl;
|
||||
#endif
|
||||
std::map<std::string,DistantMessengingInvite>::iterator tmp(it) ;
|
||||
++tmp ;
|
||||
_messenging_invites.erase(it) ;
|
||||
it = tmp ;
|
||||
}
|
||||
else
|
||||
++it ;
|
||||
|
||||
// clean dead contacts.
|
||||
//
|
||||
for(std::map<std::string,DistantMessengingContact>::iterator it(_messenging_contacts.begin());it!=_messenging_contacts.end();)
|
||||
if(it->second.pending_messages.empty() && it->second.status == RS_DISTANT_MSG_STATUS_TUNNEL_DN)
|
||||
{
|
||||
#ifdef DEBUG_DISTANT_MSG
|
||||
std::cerr << " Removing dead contact with no pending msgs and dead tunnel. hash=" << it->first << std::endl;
|
||||
#endif
|
||||
std::map<std::string,DistantMessengingContact>::iterator tmp(it) ;
|
||||
++tmp ;
|
||||
_messenging_contacts.erase(it) ;
|
||||
it = tmp ;
|
||||
}
|
||||
else
|
||||
++it ;
|
||||
}
|
||||
}
|
||||
|
||||
void p3MsgService::addVirtualPeer(const TurtleFileHash& hash, const TurtleVirtualPeerId& vpid,RsTurtleGenericTunnelItem::Direction dir)
|
||||
{
|
||||
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
|
||||
// A new tunnel has been created. We need to flush pending messages for the corresponding peer.
|
||||
|
||||
//std::map<std::string,DistantMessengingContact>::const_iterator it = _messenging_contacts.find(hash) ;
|
||||
|
||||
DistantMessengingContact& contact(_messenging_contacts[hash]) ; // possibly creates it.
|
||||
|
||||
contact.virtual_peer_id = vpid ;
|
||||
contact.last_hit_time = time(NULL) ;
|
||||
contact.status = RS_DISTANT_MSG_STATUS_TUNNEL_OK ;
|
||||
|
||||
#ifdef DEBUG_DISTANT_MSG
|
||||
std::cerr << "p3MsgService::addVirtualPeer(): adding virtual peer " << vpid << " for hash " << hash << std::endl;
|
||||
#endif
|
||||
}
|
||||
void p3MsgService::removeVirtualPeer(const TurtleFileHash& hash, const TurtleVirtualPeerId& vpid)
|
||||
{
|
||||
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
|
||||
// A new tunnel has been created. We need to flush pending messages for the corresponding peer.
|
||||
|
||||
//std::map<std::string,DistantMessengingContact>::const_iterator it = _messenging_contacts.find(hash) ;
|
||||
|
||||
DistantMessengingContact& contact(_messenging_contacts[hash]) ; // possibly creates it.
|
||||
|
||||
contact.status = RS_DISTANT_MSG_STATUS_TUNNEL_DN ;
|
||||
contact.virtual_peer_id.clear() ;
|
||||
}
|
||||
#ifdef DEBUG_DISTANT_MSG
|
||||
static void printBinaryData(void *data,uint32_t size)
|
||||
{
|
||||
static const char outl[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' } ;
|
||||
|
||||
for(uint32_t j = 0; j < size; j++)
|
||||
{
|
||||
std::cerr << outl[ ( ((uint8_t*)data)[j]>>4) ] ;
|
||||
std::cerr << outl[ ((uint8_t*)data)[j] & 0xf ] ;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void p3MsgService::sendTurtleData(const std::string& hash,RsMsgItem *msgitem)
|
||||
{
|
||||
// The item is serialized and turned into a generic turtle item.
|
||||
|
||||
uint32_t rssize = _serialiser->size(msgitem) ;
|
||||
unsigned char *data = new unsigned char[rssize] ;
|
||||
|
||||
if(!_serialiser->serialise(msgitem,data,&rssize))
|
||||
{
|
||||
std::cerr << "(EE) p3MsgService::sendTurtleData(): Serialization error." << std::endl;
|
||||
delete[] data ;
|
||||
return ;
|
||||
}
|
||||
|
||||
RsTurtleGenericDataItem *item = new RsTurtleGenericDataItem ;
|
||||
item->data_bytes = malloc(rssize) ;
|
||||
item->data_size = rssize ;
|
||||
memcpy(item->data_bytes,data,rssize) ;
|
||||
|
||||
delete[] data ;
|
||||
|
||||
#ifdef DEBUG_DISTANT_MSG
|
||||
printBinaryData(item->data_bytes,item->data_size) ;
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
// do we have a working tunnel for that hash ?
|
||||
// If not, put on the contact's waiting list.
|
||||
|
||||
std::string virtual_peer_id ;
|
||||
{
|
||||
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
|
||||
std::map<std::string,DistantMessengingContact>::const_iterator it = _messenging_contacts.find(hash) ;
|
||||
|
||||
if(it == _messenging_contacts.end())
|
||||
{
|
||||
std::cerr << "(EE) p3MsgService::sendTurtleData(): Can't find hash " << hash << " in recorded contact list." << std::endl;
|
||||
delete[] data ;
|
||||
return ;
|
||||
}
|
||||
|
||||
if(!it->second.status == RS_DISTANT_MSG_STATUS_TUNNEL_OK)
|
||||
{
|
||||
std::cerr << "p3MsgService::sendTurtleData(): tunnel is not ok. Putting items on waiting list." << std::endl;
|
||||
return ;
|
||||
}
|
||||
virtual_peer_id = it->second.virtual_peer_id ;
|
||||
}
|
||||
#ifdef DEBUG_DISTANT_MSG
|
||||
std::cerr << "p3MsgService::sendTurtleData(): Sending through virtual peer: " << virtual_peer_id << std::endl;
|
||||
std::cerr << " item->data_size = " << item->data_size << std::endl;
|
||||
std::cerr << " data = " ;
|
||||
#endif
|
||||
|
||||
mTurtle->sendTurtleData(virtual_peer_id,item) ;
|
||||
}
|
||||
|
||||
void p3MsgService::receiveTurtleData(RsTurtleGenericTunnelItem *gitem,const std::string& hash,
|
||||
const std::string& virtual_peer_id,RsTurtleGenericTunnelItem::Direction direction)
|
||||
{
|
||||
RsTurtleGenericDataItem *item = dynamic_cast<RsTurtleGenericDataItem*>(gitem) ;
|
||||
|
||||
if(item == NULL)
|
||||
{
|
||||
std::cerr << "(EE) p3MsgService::receiveTurtleData(): item is not a data item. That is an error." << std::endl;
|
||||
return ;
|
||||
}
|
||||
#ifdef DEBUG_DISTANT_MSG
|
||||
std::cerr << "p3MsgService::sendTurtleData(): Receiving through virtual peer: " << virtual_peer_id << std::endl;
|
||||
std::cerr << " gitem->data_size = " << item->data_size << std::endl;
|
||||
std::cerr << " data = " ;
|
||||
printBinaryData(item->data_bytes,item->data_size) ;
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
{
|
||||
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
|
||||
std::map<std::string,DistantMessengingContact>::iterator it = _messenging_contacts.find(hash) ;
|
||||
|
||||
if(it == _messenging_contacts.end())
|
||||
{
|
||||
std::cerr << "(EE) p3MsgService::sendTurtleData(): Can't find hash " << hash << " in recorded contact list." << std::endl;
|
||||
return ;
|
||||
}
|
||||
|
||||
it->second.status = RS_DISTANT_MSG_STATUS_TUNNEL_OK ;
|
||||
it->second.last_hit_time = time(NULL) ;
|
||||
}
|
||||
|
||||
RsItem *itm = _serialiser->deserialise(item->data_bytes,&item->data_size) ;
|
||||
|
||||
RsMsgItem *mitm = dynamic_cast<RsMsgItem*>(itm) ;
|
||||
|
||||
if(mitm != NULL)
|
||||
{
|
||||
mitm->PeerId(hash) ;
|
||||
handleIncomingItem(mitm) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "(EE) p3MsgService::receiveTurtleData(): received item is not a RsMsgItem!!" << std::endl;
|
||||
delete itm ;
|
||||
}
|
||||
}
|
||||
|
||||
void p3MsgService::sendPrivateMsgItem(RsMsgItem *msgitem)
|
||||
{
|
||||
#ifdef DEBUG_DISTANT_MSG
|
||||
std::cerr << "p3MsgService::sendDistanteMsgItem(): sending distant msg item to peer " << msgitem->PeerId() << std::endl;
|
||||
std::cerr << " asking for tunnels" << std::endl;
|
||||
std::cerr << " recording msg info" << std::endl;
|
||||
#endif
|
||||
const std::string& hash = msgitem->PeerId() ;
|
||||
rsTurtle->monitorTunnels(hash,this) ; // create a tunnel for it, and put the msg on the waiting list.
|
||||
|
||||
{
|
||||
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
|
||||
|
||||
// allocate a new contact. If it does not exist, set its tunnel state to DN
|
||||
//
|
||||
std::map<std::string,DistantMessengingContact>::iterator it = _messenging_contacts.find(hash) ;
|
||||
|
||||
DistantMessengingContact& contact( _messenging_contacts[hash] ) ;
|
||||
|
||||
if(it == _messenging_contacts.end())
|
||||
it->second.status = RS_DISTANT_MSG_STATUS_TUNNEL_DN ;
|
||||
|
||||
contact.pending_messages.push_back(msgitem) ; // record the msg to be sent.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -42,10 +42,12 @@
|
|||
#include "services/p3service.h"
|
||||
#include "serialiser/rsmsgitems.h"
|
||||
#include "util/rsthreads.h"
|
||||
#include "turtle/p3turtle.h"
|
||||
#include "turtle/turtleclientservice.h"
|
||||
|
||||
class p3LinkMgr;
|
||||
|
||||
class p3MsgService: public p3Service, public p3Config, public pqiMonitor
|
||||
class p3MsgService: public p3Service, public p3Config, public pqiMonitor, public RsTurtleClientService
|
||||
{
|
||||
public:
|
||||
p3MsgService(p3LinkMgr *lm);
|
||||
|
@ -55,6 +57,7 @@ bool getMessageSummaries(std::list<MsgInfoSummary> &msgList);
|
|||
bool getMessage(const std::string &mid, MessageInfo &msg);
|
||||
void getMessageCount(unsigned int *pnInbox, unsigned int *pnInboxNew, unsigned int *pnOutbox, unsigned int *pnDraftbox, unsigned int *pnSentbox, unsigned int *pnTrashbox);
|
||||
|
||||
bool decryptMessage(const std::string& mid) ;
|
||||
bool removeMsgId(const std::string &mid);
|
||||
bool markMsgIdRead(const std::string &mid, bool bUnreadByUser);
|
||||
bool setMsgFlag(const std::string &mid, uint32_t flag, uint32_t mask);
|
||||
|
@ -97,7 +100,51 @@ virtual void statusChange(const std::list<pqipeer> &plist);
|
|||
int checkOutgoingMessages();
|
||||
/*** Overloaded from pqiMonitor ***/
|
||||
|
||||
/*** overloaded from p3turtle ***/
|
||||
|
||||
void connectToTurtleRouter(p3turtle *) ;
|
||||
|
||||
struct DistantMessengingInvite
|
||||
{
|
||||
time_t time_of_validity ;
|
||||
};
|
||||
struct DistantMessengingContact
|
||||
{
|
||||
time_t last_hit_time ;
|
||||
std::string virtual_peer_id ;
|
||||
uint32_t status ;
|
||||
std::vector<RsMsgItem*> pending_messages ;
|
||||
};
|
||||
|
||||
bool createDistantOfflineMessengingInvite(time_t time_of_validity,TurtleFileHash& hash) ;
|
||||
bool getDistantOfflineMessengingInvites(std::vector<DistantOfflineMessengingInvite>& invites) ;
|
||||
void sendPrivateMsgItem(RsMsgItem *) ;
|
||||
|
||||
private:
|
||||
// This maps contains the current invitations to respond to.
|
||||
//
|
||||
std::map<std::string,DistantMessengingInvite> _messenging_invites ;
|
||||
|
||||
// This contains the ongoing tunnel handling contacts.
|
||||
//
|
||||
std::map<std::string,DistantMessengingContact> _messenging_contacts ;
|
||||
|
||||
// Overloaded from RsTurtleClientService
|
||||
|
||||
virtual bool handleTunnelRequest(const std::string& hash,const std::string& peer_id) ;
|
||||
virtual void receiveTurtleData(RsTurtleGenericTunnelItem *item,const std::string& hash,const std::string& virtual_peer_id,RsTurtleGenericTunnelItem::Direction direction) ;
|
||||
void addVirtualPeer(const TurtleFileHash&, const TurtleVirtualPeerId&,RsTurtleGenericTunnelItem::Direction dir) ;
|
||||
void removeVirtualPeer(const TurtleFileHash&, const TurtleVirtualPeerId&) ;
|
||||
|
||||
// Utility functions
|
||||
|
||||
bool encryptMessage(const std::string& pgp_id,RsMsgItem *msg) ;
|
||||
|
||||
void manageDistantPeers() ;
|
||||
void sendTurtleData(const std::string& hash,RsMsgItem *) ;
|
||||
void handleIncomingItem(RsMsgItem *) ;
|
||||
|
||||
p3turtle *mTurtle ;
|
||||
|
||||
uint32_t getNewUniqueMsgId();
|
||||
int sendMessage(RsMsgItem *item);
|
||||
|
@ -118,6 +165,7 @@ void initStandardTagTypes();
|
|||
/* Mutex Required for stuff below */
|
||||
|
||||
RsMutex mMsgMtx;
|
||||
RsMsgSerialiser *_serialiser ;
|
||||
|
||||
/* stored list of messages */
|
||||
std::map<uint32_t, RsMsgItem *> imsg;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue