diff options
Diffstat (limited to 'libktorrent/kademlia/kbucket.h')
-rw-r--r-- | libktorrent/kademlia/kbucket.h | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/libktorrent/kademlia/kbucket.h b/libktorrent/kademlia/kbucket.h new file mode 100644 index 0000000..139ce10 --- /dev/null +++ b/libktorrent/kademlia/kbucket.h @@ -0,0 +1,212 @@ +/*************************************************************************** + * Copyright (C) 2005 by Joris Guisson * + * [email protected] * + * * + * 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 <qvaluelist.h> +#include <util/constants.h> +#include <ksocketaddress.h> +#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 + { + Q_OBJECT + + Uint32 idx; + QValueList<KBucketEntry> entries,pending_entries; + RPCServer* srv; + Node* node; + QMap<RPCCall*,KBucketEntry> 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 |