/* * bitdht/bdhash.cc * * BitDHT: An Flexible DHT library. * * Copyright 2010 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 3 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 "bitdht@lunamutt.com". * */ #include "bitdht/bdhash.h" #include "bitdht/bdstddht.h" #include bdHashEntry::bdHashEntry(std::string value, std::string secret, time_t lifetime, time_t store) :mValue(value), mStoreTS(store), mSecret(secret), mLifetime(lifetime) { return; } /**************************** class bdHashSet ********************************/ bdHashSet::bdHashSet(bdNodeId *id) :mId(*id) { return; } int bdHashSet::search(std::string key, uint32_t maxAge, std::list &entries) { std::multimap::iterator sit, eit, it; sit = mEntries.lower_bound(key); eit = mEntries.upper_bound(key); time_t now = time(NULL); for(it = sit; it != eit; it++) { time_t age = now - it->second.mStoreTS; if (age < (int32_t) maxAge) { entries.push_back(it->second); } } return (0 < entries.size()); } /*** * With modification. * If there is no secret -> it cannot be deleted (must timeout), but can be extended. * If there is a secret -> must include it to modify. * * Therefore if identical entry without secret comes along - what do I do? * -> create duplicate? */ int bdHashSet::modify(std::string key, bdHashEntry *entry, uint32_t modFlags) { std::multimap::iterator sit, eit, it; sit = mEntries.lower_bound(key); eit = mEntries.upper_bound(key); time_t now = time(NULL); bool updated = false; for(it = sit; it != eit; it++) { /* check it all */ if (it->second.mValue == entry->mValue) { bool noSecret = (it->second.mSecret == ""); bool sameSecret = (it->second.mSecret == entry->mSecret); bool update = false; if (noSecret && sameSecret) { /* only allowed to increase lifetime */ if (modFlags == BITDHT_HASH_ENTRY_ADD) { time_t existKillTime = it->second.mLifetime + it->second.mStoreTS; time_t newKillTime = entry->mLifetime + now; if (newKillTime > existKillTime) { update = true; } } } else if (sameSecret) { if (modFlags == BITDHT_HASH_ENTRY_ADD) { update = true; } else if (modFlags == BITDHT_HASH_ENTRY_DELETE) { /* do it here */ mEntries.erase(it); return 1; } } if (update) { it->second.mStoreTS = now; it->second.mLifetime = entry->mLifetime; updated = true; } } } if ((!updated) && (modFlags == BITDHT_HASH_ENTRY_ADD)) { /* create a new entry */ bdHashEntry newEntry(entry->mValue, entry->mSecret, entry->mLifetime, now); mEntries.insert(std::pair(key, newEntry)); updated = true; } return updated; } int bdHashSet::printHashSet(std::ostream &out) { time_t now = time(NULL); std::multimap::iterator it; out << "Hash: "; bdStdPrintNodeId(out, &mId); // Allowing "Std" as we dont need dht functions everywhere. out << std::endl; for(it = mEntries.begin(); it != mEntries.end();it++) { time_t age = now - it->second.mStoreTS; out << "\tK:" << bdStdConvertToPrintable(it->first); out << " V:" << bdStdConvertToPrintable(it->second.mValue); out << " A:" << age << " L:" << it->second.mLifetime; out << " S:" << bdStdConvertToPrintable(it->second.mSecret); out << std::endl; } return 1; } int bdHashSet::cleanupHashSet(uint32_t maxAge) { time_t now = time(NULL); /* this is nasty... but don't know how to effectively remove from multimaps * * Must do full repeat for each removal. */ std::multimap::iterator it; for(it = mEntries.begin(); it != mEntries.end();) { time_t age = now - it->second.mStoreTS; if ((age > (int32_t) maxAge) || (age > it->second.mLifetime)) { mEntries.erase(it); it = mEntries.begin(); } else { it++; } } return 1; } /******************************* class bdHashSpace ***************************/ bdHashSpace::bdHashSpace() { return; } /* accessors */ int bdHashSpace::search(bdNodeId *id, std::string key, uint32_t maxAge, std::list &entries) { std::map::iterator it; it = mHashTable.find(*id); if (it == mHashTable.end()) { /* no entry */ return 1; } return it->second.search(key, maxAge, entries); } int bdHashSpace::modify(bdNodeId *id, std::string key, bdHashEntry *entry, uint32_t modFlags) { std::map::iterator it; it = mHashTable.find(*id); if (it == mHashTable.end()) { if (modFlags == BITDHT_HASH_ENTRY_DELETE) { /* done already */ return 1; } //mHashTable[*id] = bdHashSet(id); mHashTable.insert(std::pair(*id, bdHashSet(id))); it = mHashTable.find(*id); } return it->second.modify(key, entry, modFlags); } int bdHashSpace::printHashSpace(std::ostream &out) { std::map::iterator it; out << "bdHashSpace::printHashSpace()" << std::endl; out << "--------------------------------------------" << std::endl; for(it = mHashTable.begin(); it != mHashTable.end(); it++) { it->second.printHashSet(out); } out << "--------------------------------------------" << std::endl; return 1; } int bdHashSpace::cleanHashSpace(bdNodeId *min, bdNodeId *max, time_t maxAge) { std::map::iterator it; std::list eraseList; std::list::iterator eit; for(it = mHashTable.begin(); it != mHashTable.end(); it++) { if ((it->first < *min) || (*max < it->first)) { /* schedule for erasure */ eraseList.push_back(it->first); } else { /* clean up Hash Set */ it->second.cleanupHashSet(maxAge); } } /* cleanup */ while(eraseList.size() > 0) { bdNodeId &eId = eraseList.front(); it = mHashTable.find(eId); if (it != mHashTable.end()) { mHashTable.erase(it); } } return 1; } int bdHashSpace::clear() { mHashTable.clear(); return 1; }