/*************************************************************************** * Copyright (C) 2005 by Joris Guisson * * joris.guisson@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #ifndef DHTKBUCKET_H #define DHTKBUCKET_H #include #include #include #include "key.h" #include "rpccall.h" #include "task.h" using bt::Uint32; using bt::Uint16; using bt::Uint8; using KNetwork::KInetSocketAddress; namespace bt { class File; } namespace dht { class RPCServer; class KClosestNodesSearch; class Node; class Task; const Uint32 K = 8; const Uint32 BUCKET_MAGIC_NUMBER = 0xB0C4B0C4; const Uint32 BUCKET_REFRESH_INTERVAL = 15 * 60 * 1000; // const Uint32 BUCKET_REFRESH_INTERVAL = 120 * 1000; struct BucketHeader { Uint32 magic; Uint32 index; Uint32 num_entries; }; /** * @author Joris Guisson * * Entry in a KBucket, it basically contains an ip_address of a node, * the udp port of the node and a node_id. */ class KBucketEntry { KInetSocketAddress addr; Key node_id; bt::TimeStamp last_responded; Uint32 failed_queries; Uint32 questionable_pings; public: /** * Constructor, sets everything to 0. * @return */ KBucketEntry(); /** * Constructor, set the ip, port and key * @param addr socket address * @param id ID of node */ KBucketEntry(const KInetSocketAddress & addr,const Key & id); /** * Copy constructor. * @param other KBucketEntry to copy * @return */ KBucketEntry(const KBucketEntry & other); /// Destructor virtual ~KBucketEntry(); /** * Assignment operator. * @param other Node to copy * @return this KBucketEntry */ KBucketEntry & operator = (const KBucketEntry & other); /// Equality operator bool operator == (const KBucketEntry & entry) const; /// Get the socket address of the node const KInetSocketAddress & getAddress() const {return addr;} /// Get it's ID const Key & getID() const {return node_id;} /// Is this node a good node bool isGood() const; /// Is this node questionable (haven't heard from it in the last 15 minutes) bool isQuestionable() const; /// Is it a bad node. (Hasn't responded to a query bool isBad() const; /// Signal the entry that the peer has responded void hasResponded(); /// A request timed out void requestTimeout() {failed_queries++;} /// The entry has been pinged because it is questionable void onPingQuestionable() {questionable_pings++;} /// The null entry static KBucketEntry null; }; /** * @author Joris Guisson * * A KBucket is just a list of KBucketEntry objects. * The list is sorted by time last seen : * The first element is the least recently seen, the last * the most recently seen. */ class KBucket : public RPCCallListener { TQ_OBJECT Uint32 idx; TQValueList entries,pending_entries; RPCServer* srv; Node* node; TQMap pending_entries_busy_pinging; mutable bt::TimeStamp last_modified; Task* refresh_task; public: KBucket(Uint32 idx,RPCServer* srv,Node* node); virtual ~KBucket(); /** * Inserts an entry into the bucket. * @param entry The entry to insert */ void insert(const KBucketEntry & entry); /// Get the least recently seen node const KBucketEntry & leastRecentlySeen() const {return entries[0];} /// Get the number of entries Uint32 getNumEntries() const {return entries.count();} /// See if this bucket contains an entry bool contains(const KBucketEntry & entry) const; /** * Find the K closest entries to a key and store them in the KClosestNodesSearch * object. * @param kns The object to storre the search results */ void findKClosestNodes(KClosestNodesSearch & kns); /** * A peer failed to respond * @param addr Address of the peer */ bool onTimeout(const KInetSocketAddress & addr); /// Check if the bucket needs to be refreshed bool needsToBeRefreshed() const; /// save the bucket to a file void save(bt::File & fptr); /// Load the bucket from a file void load(bt::File & fptr,const BucketHeader & hdr); /// Update the refresh timer of the bucket void updateRefreshTimer(); /// Set the refresh task void setRefreshTask(Task* t); private: virtual void onResponse(RPCCall* c,MsgBase* rsp); virtual void onTimeout(RPCCall* c); void pingQuestionable(const KBucketEntry & replacement_entry); bool replaceBadEntry(const KBucketEntry & entry); private slots: void onFinished(Task* t); }; } #endif