From 8ad457e011b2659b830a06dc5440029a0ea1da96 Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 28 Feb 2009 18:19:00 +0000 Subject: [PATCH] Started turtle hopping implementation. Not yet functional nor compilable. git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@1059 b45a01b8-16f6-495d-af2f-9b41ad6348cc --- libretroshare/src/serialiser/rsserviceids.h | 1 + libretroshare/src/services/p3turtle.cc | 495 ++++++++++++++++++++ libretroshare/src/services/p3turtle.h | 141 ++++++ 3 files changed, 637 insertions(+) create mode 100644 libretroshare/src/services/p3turtle.cc create mode 100644 libretroshare/src/services/p3turtle.h diff --git a/libretroshare/src/serialiser/rsserviceids.h b/libretroshare/src/serialiser/rsserviceids.h index 8908a8b89..53c26befc 100644 --- a/libretroshare/src/serialiser/rsserviceids.h +++ b/libretroshare/src/serialiser/rsserviceids.h @@ -45,6 +45,7 @@ const uint16_t RS_SERVICE_TYPE_RANK = 0x0002; const uint16_t RS_SERVICE_TYPE_DISC = 0x0011; const uint16_t RS_SERVICE_TYPE_CHAT = 0x0012; const uint16_t RS_SERVICE_TYPE_MSG = 0x0013; +const uint16_t RS_SERVICE_TYPE_TURTLE = 0x0014; /* Combined Cache/Service ids */ diff --git a/libretroshare/src/services/p3turtle.cc b/libretroshare/src/services/p3turtle.cc new file mode 100644 index 000000000..be4f7611a --- /dev/null +++ b/libretroshare/src/services/p3turtle.cc @@ -0,0 +1,495 @@ +/* + * libretroshare/src/services: p3disc.cc + * + * Services for RetroShare. + * + * Copyright 2004-2008 by Robert Fernie. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License Version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems to "retroshare@lunamutt.com". + * + */ + + +#include "rsiface/rsiface.h" +#include "rsiface/rspeers.h" +#include "services/p3disc.h" + +#include "pqi/p3authmgr.h" +#include "pqi/p3connmgr.h" + +#include +#include +#include + +const uint8_t RS_TURTLE_SUBTYPE_SEARCH_REQUEST = 0x01; +const uint8_t RS_TURTLE_SUBTYPE_SEARCH_RESULT = 0x02; + +#include + +#include "util/rsdebug.h" +#include "util/rsprint.h" + +// Operating System specific includes. +#include "pqi/pqinetwork.h" + +/* DISC FLAGS */ + +/***** + * #define P3DISC_DEBUG 1 + ****/ + +/*********** NOTE *************** + * + * Only need Mutexs for neighbours information + */ + +/****************************************************************************************** + ****************************** NEW DISCOVERY ******************************************* + ****************************************************************************************** + *****************************************************************************************/ + +p3turtle::p3turtle(p3AuthMgr *am, p3ConnectMgr *cm) :p3Service(RS_SERVICE_TYPE_TURTLE), mAuthMgr(am), mConnMgr(cm) +{ + RsStackMutex stack(mDiscMtx); /********** STACK LOCKED MTX ******/ + + addSerialType(new RsTurtleSerialiser()); +} + +int p3turtle::tick() +{ + handleIncoming(); // handle incoming packets + handleOutgoing(); // handle outgoing packets + + autoclean() ; // clean old/unused tunnels and search requests. +} + +int p3turtle::handleIncoming() +{ +#ifdef DEBUG_TURTLE + std::cerr << "p3turtle::handleIncoming()"; + std::cerr << std::endl; +#endif + + { + RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ + } + + int nhandled = 0; + // While messages read + // + RsItem *item = NULL; + + while(NULL != (item = recvItem())) + { + nhandled++; + + switch(item->subType()) + { + case RS_TURTLE_SUBTYPE_SEARCH_REQUEST: handleSearchRequest(dynamic_cast(item)) ; + break ; + + case RS_TURTLE_SUBTYPE_SEARCH_RESULT : handleSearchResult(dynamic_cast(item)) ; + break ; + + // Here will also come handling of file transfer requests, tunnel digging/closing, etc. + default: + std::cerr << "p3turtle::handleIncoming: Unknown packet subtype " << item->subType() << std::endl ; + } + delete item; + } + + return nhandled; +} + +void p3turtle::handleSearchRequest(const RsSearchRequestItem *item) +{ + // take a look at the item: + // - If the item destimation is + + // If the item contains an already handled search request, give up. This + // happens when the same search request gets relayed by different peers + // + if(requests_origins.find(item->request_id) != requests_origins.end()) + return ; + + // This is a new request. Let's add it to the request map, and forward it to + // open peers. + + requests_origins[item->request_id] = item->peerId() ; + + // Perform local search. If something found, forward the search result back. + + std::map result ; + performLocalSearch(item->match_string,result) ; + + if(!result.empty()) + { + // do something + + // forward item back + RsTurtleSearchResultItem *res_item = new RsTurtleSearchResultItem ; + + res_item->depth = 0 ; + res_item->result = result ; + res_item->request_id = item->request_id ; + res_item->peer_id = item->peer_id ; // send back to the same guy + + sendItem(res_item) ; + } + + // If search depth not too large, also forward this search request to all other peers. + // + if(item->depth < TURTLE_MAX_SEARCH_DEPTH) + for(std::map<>::const_iterator it(openned_peers.begin());it!=openned_peers.end();++it) + if(*it != item->peerId()) + { + // Copy current item and modify it. + RsTurtleSearchRequestItem *fwd_item = new RsTurtleSearchRequestItem(item) ; + + ++(fwd_item->depth) ; // increase search depth + fwd_item->peerId = *it ; + + sendItem(fwd_item) ; + } +} + +void p3turtle::handleSearchResult(const RsSearchResultItem *item) +{ + // Find who actually sent the corresponding request. + // + std::map::const_iterator it = requests_origins.find(item->request_id) ; + + if(it == requests_origins.end()) + { + // This is an error: how could we receive a search result corresponding to a search item we + // have forwarded but that it not in the list ?? + + std::cerr << __PRETTY_FUNCTION__ << ": search result has no peer direction!" << std::endl ; + delete item ; + return ; + } + + // Is this result's target actually ours ? + + if(it->second == own_peer_id) + returnSearchResult(item) ; // Yes, so send upward. + else + { // Nope, so forward it back. + RsSearchResultItem *fwd_item = new RsSearchResultItem(item) ; // copy the item + + ++(fwd_item->depth) ; // increase depth + + // normally here, we should setup the forward adress, so that the owner's of the files found can be further reached by a tunnel. + + fwd_item->peerId = it->second ; + + sendItem(fwd_item) ; + } +} + +/************* from pqiMonitor *******************/ +void p3turtle::statusChange(const std::list &plist) +{ +#ifdef TO_DO + /* get a list of all online peers */ + std::list onlineIds; + mConnMgr->getOnlineList(onlineIds); + + std::list::const_iterator pit; + /* if any have switched to 'connected' then we notify */ + for(pit = plist.begin(); pit != plist.end(); pit++) + { + if ((pit->state & RS_PEER_S_FRIEND) && + (pit->actions & RS_PEER_CONNECTED)) + { + /* send our details to them */ + sendOwnDetails(pit->id); + } + } +#endif +} + +#ifdef A_VIRER + +void p3disc::respondToPeer(std::string id) +{ + /* get a peer lists */ + +#ifdef P3DISC_DEBUG + std::cerr << "p3disc::respondToPeer() id: " << id; + std::cerr << std::endl; +#endif + + std::list friendIds; + std::list onlineIds; + std::list::iterator it; + + mConnMgr->getFriendList(friendIds); + mConnMgr->getOnlineList(onlineIds); + + /* Check that they have DISC on */ + { + /* get details */ + peerConnectState detail; + if (!mConnMgr->getFriendNetStatus(id, detail)) + { + /* major error! */ + return; + } + + if (detail.visState & RS_VIS_STATE_NODISC) + { + /* don't have DISC enabled */ + return; + } + } + + /* send them a list of all friend's details */ + for(it = friendIds.begin(); it != friendIds.end(); it++) + { + /* get details */ + peerConnectState detail; + if (!mConnMgr->getFriendNetStatus(*it, detail)) + { + /* major error! */ + continue; + } + + if (!(detail.visState & RS_VIS_STATE_NODISC)) + { + sendPeerDetails(id, *it); /* (dest (to), source (cert)) */ + } + } + + /* send their details to all online peers */ + for(it = onlineIds.begin(); it != onlineIds.end(); it++) + { + peerConnectState detail; + if (!mConnMgr->getFriendNetStatus(*it, detail)) + { + /* major error! */ + continue; + } + + if (!(detail.visState & RS_VIS_STATE_NODISC)) + { + sendPeerDetails(*it, id); /* (dest (to), source (cert)) */ + } + } +} + +/*************************************************************************************/ +/* Output Network Msgs */ +/*************************************************************************************/ +void p3disc::sendOwnDetails(std::string to) +{ + /* setup: + * IP local / external + * availability (TCP LOCAL / EXT, UDP ...) + */ + + // Then send message. + { +#ifdef P3DISC_DEBUG + std::ostringstream out; + out << "p3disc::sendOwnDetails()"; + out << "Constructing a RsDiscItem Message!" << std::endl; + out << "Sending to: " << to; + std::cerr << out.str() << std::endl; +#endif + } + + // Construct a message + RsDiscItem *di = new RsDiscItem(); + + /* components: + * laddr + * saddr + * contact_tf + * discFlags + */ + + peerConnectState detail; + if (!mConnMgr->getOwnNetStatus(detail)) + { + /* major error! */ + return; + } + + // Fill the message + di -> PeerId(to); + di -> laddr = detail.localaddr; + di -> saddr = detail.serveraddr; + di -> contact_tf = 0; + + /* construct disc flags */ + di -> discFlags = 0; + if (!(detail.visState & RS_VIS_STATE_NODISC)) + { + di->discFlags |= P3DISC_FLAGS_USE_DISC; + } + + if (!(detail.visState & RS_VIS_STATE_NODHT)) + { + di->discFlags |= P3DISC_FLAGS_USE_DHT; + } + + if ((detail.netMode & RS_NET_MODE_EXT) || + (detail.netMode & RS_NET_MODE_UPNP)) + { + di->discFlags |= P3DISC_FLAGS_EXTERNAL_ADDR; + } + else if (detail.netMode & RS_NET_MODE_UDP) + { + di->discFlags |= P3DISC_FLAGS_STABLE_UDP; + } + + di->discFlags |= P3DISC_FLAGS_OWN_DETAILS; + + /* send msg */ + sendItem(di); +} + + /* (dest (to), source (cert)) */ +void p3disc::sendPeerDetails(std::string to, std::string about) +{ + /* setup: + * Certificate. + * IP local / external + * availability ... + * last connect (0) if online. + */ + + /* send it off */ + { +#ifdef P3DISC_DEBUG + std::ostringstream out; + out << "p3disc::sendPeerDetails()"; + out << " Sending details of: " << about; + out << " to: " << to << std::endl; + std::cerr << out.str() << std::endl; +#endif + } + + + peerConnectState detail; + if (!mConnMgr->getFriendNetStatus(about, detail)) + { + /* major error! */ + return; + } + + // Construct a message + RsDiscReply *di = new RsDiscReply(); + + // Fill the message + // Set Target as input cert. + di -> PeerId(to); + di -> aboutId = about; + + // set the server address. + di -> laddr = detail.localaddr; + di -> saddr = detail.serveraddr; + + if (detail.state & RS_PEER_S_CONNECTED) + { + di -> contact_tf = 0; + } + else + { + di -> contact_tf = convertTDeltaToTRange(time(NULL) - detail.lastcontact); + } + + /* construct disc flags */ + di->discFlags = 0; + + /* NOTE we should not be sending packet if NODISC is set.... + * checked elsewhere... so don't check. + */ + di->discFlags |= P3DISC_FLAGS_USE_DISC; + + if (!(detail.visState & RS_VIS_STATE_NODHT)) + { + di->discFlags |= P3DISC_FLAGS_USE_DHT; + } + + if (detail.netMode & RS_NET_MODE_EXT) + { + di->discFlags |= P3DISC_FLAGS_EXTERNAL_ADDR; + } + else if (detail.netMode & RS_NET_MODE_UDP) + { + di->discFlags |= P3DISC_FLAGS_STABLE_UDP; + } + + if (detail.state & RS_PEER_S_CONNECTED) + { + di->discFlags |= P3DISC_FLAGS_PEER_ONLINE; + } + + // Add 3rd party trust info + // We look at peers that trust 'to', by looking into 'to''s tigners list. The problem is that + // signers are accessible through their names instead of their id, so there is ambiguity if too peers + // have the same names. @DrBob: that would be cool to save signers using their ids... + // + RsPeerDetails pd ; + std::string name = rsPeers->getPeerName(about) ; + if(rsPeers->getPeerDetails(to,pd)) + for(std::list::const_iterator it(pd.signers.begin());it!=pd.signers.end();++it) + if(*it == name) + { + di->discFlags |= P3DISC_FLAGS_PEER_TRUSTS_ME; +#ifdef P3DISC_DEBUG + std::cerr << " Peer " << about << "(" << name << ")" << " is trusting " << to << ", sending info." << std::endl ; +#endif + } + + uint32_t certLen = 0; + + unsigned char **binptr = (unsigned char **) &(di -> certDER.bin_data); + + mAuthMgr->SaveCertificateToBinary(about, binptr, &certLen); +#ifdef P3DISC_DEBUG + std::cerr << "Saved certificate to binary in p3discReply. Length=" << certLen << std::endl ; +#endif + if (certLen > 0) + { + di -> certDER.bin_len = certLen; +#ifdef P3DISC_DEBUG + std::cerr << "Cert Encoded(" << certLen << ")" << std::endl; +#endif + } + else + { +#ifdef P3DISC_DEBUG + std::cerr << "Failed to Encode Cert" << std::endl; +#endif + di -> certDER.bin_len = 0; + } + + // Send off message + sendItem(di); + +#ifdef P3DISC_DEBUG + std::cerr << "Sent DI Message" << std::endl; +#endif +} + +#endif + + + diff --git a/libretroshare/src/services/p3turtle.h b/libretroshare/src/services/p3turtle.h new file mode 100644 index 000000000..76c01143d --- /dev/null +++ b/libretroshare/src/services/p3turtle.h @@ -0,0 +1,141 @@ +/* + * libretroshare/src/services: p3turtle.h + * + * Services for RetroShare. + * + * Copyright 2004-2008 by Robert Fernie. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License Version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems to "retroshare@lunamutt.com". + * + */ + +// This class implements the turtle hopping router. It basically serves as +// - a cache of turtle tunnels which are the communicating ways between distant peers. +// - turtle tunnels are either end-point tunnels, or transitory points, in which case items are just +// re-serialized and passed on along the tunnel. +// - turtle tunnels are dug on request when calling diggTurtleTunnel(const std::string& hash) +// this command lets a trace in each peer along the tunnel of where +// packets come from and where they should go. Doing so, once a tunnel is +// dug, packets are directly forwarded to the correct peer. +// - an entry point for search request from the interface +// - search results, as they come back, are forwarded upwards with some additional info: +// - depth // depth of the file. This is here for debug bug will disapear for anonymity. +// - peer id // peer id owning the file. This is here for debug bug will disapear for anonymity. +// - hash // hash of the file found +// - name // name of the file found +// - search request id. // +// +#ifndef MRK_PQI_TURTLE_H +#define MRK_PQI_TURTLE_H + +#include +#include + +// system specific network headers +#include "pqi/pqinetwork.h" +#include "pqi/pqi.h" +#include "pqi/pqimonitor.h" +#include "serialiser/rsdiscitems.h" +#include "services/p3service.h" + +class p3AuthMgr; +class p3ConnectMgr; + +typedef uint32_t TurtleRequestId ; +typedef std::string TurtlePeerId ; + +class RsTurtleItem: public RsItem +{ + public: + virtual void serialize(void *& data,uint32_t& size) {} // isn't it better that items can (de)serialize themselves ? + virtual void deserialize(const void *data,uint32_t size) {} + + virtual int size() const ; +}; + +class RsTurtleSearchResultItem: public RsTurtleItem +{ + public: + uint16_t depth ; + uint8_t peer_id[16]; // peer id. This will eventually be obfuscated in some way. + + TurtleRequestId request_id ; // randomly generated request id. + + std::map result ; +// uint8_t hash[20] ; // sha1 hash of the file found +// std::string filename ; // name of the file found +}; + +class RsTurtleSearchRequestItem: public RsTurtleItem +{ + public: + std::string match_string ; // string to match + uint32_t request_id ; // randomly generated request id. + uint16_t depth ; // Used for limiting search depth. +}; + +class TurtleTunnel +{ + public: + TurtlePeerId in ; // where packets come from + TurtlePeerId out ; // where packets should go + uint32_t time_stamp ; // last time the tunnel was actually used. Used for cleaning old tunnels. +}; + +class p3turtle: public p3Service, public pqiMonitor +{ + public: + p3turtle(p3AuthMgr *am, p3ConnectMgr *cm); + + // Lauches a search request through the pipes, and immediately returns + // the request id, which will be further used by the gui to store results + // as they come back. + // + TurtleRequestId performSearch(const std::string& string_to_match) ; + + /************* from pqiMonitor *******************/ + // Informs the turtle router that some peers are (dis)connected. This should initiate digging new tunnels, + // and closing other tunnels. + // + virtual void statusChange(const std::list &plist); + + /************* from pqiMonitor *******************/ + + // Handles incoming and outgoing packets, sort search requests and + // forward info upward. + int tick(); + + private: + inline uint32_t generateRandomRequestId() const { return lrand48() ; } + + /* Network Input */ + int handleIncoming(); + + void recvSearchRequest(RsTurtleSearchRequestItem *item); + + std::map request_origins ; // keeps trace of who emmitted a given request + std::map file_tunnels ; // stores adequate tunnels for each file hash. + + p3AuthMgr *mAuthMgr; + p3ConnectMgr *mConnMgr; + + /* data */ + RsMutex mTurtleMtx; +}; + +#endif +