/* * This file is part of mlDHT. * * mlDHT 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. * * mlDHT 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 mlDHT. If not, see <http://www.gnu.org/licenses/>. */ package lbms.plugins.mldht.kad.tasks; import lbms.plugins.mldht.kad.DHTConstants; import lbms.plugins.mldht.kad.KBucketEntry; import lbms.plugins.mldht.kad.Key; import lbms.plugins.mldht.kad.Node; import lbms.plugins.mldht.kad.RPCCall; import lbms.plugins.mldht.kad.RPCServer; import lbms.plugins.mldht.kad.messages.AnnounceRequest; import lbms.plugins.mldht.kad.messages.MessageBase; import java.util.Map; import java.util.NavigableMap; import java.util.TreeMap; /** * @author Damokles * */ public class AnnounceTask extends TargetedTask { private int port; private boolean isSeed; NavigableMap<KBucketEntry, byte[]> todo; public AnnounceTask (RPCServer rpc, Node node, Key info_hash, int port, Map<KBucketEntry, byte[]> candidatesAndTokens) { super(info_hash, rpc, node); this.port = port; this.todo = new TreeMap<>(new KBucketEntry.DistanceOrder(info_hash)); todo.putAll(candidatesAndTokens); } public void setSeed(boolean isSeed) { this.isSeed = isSeed; } @Override void callFinished (RPCCall c, MessageBase rsp) {} @Override void callTimeout (RPCCall c) {} @Override void update () { for(;;) { if(getRecvResponses() >= DHTConstants.MAX_ENTRIES_PER_BUCKET) return; RequestPermit p = checkFreeSlot(); // we don't care about stalls here; if(p != RequestPermit.FREE_SLOT) return; Map.Entry<KBucketEntry, byte[]> me = todo.firstEntry(); if(me == null) return; KBucketEntry e = me.getKey(); AnnounceRequest anr = new AnnounceRequest(targetKey, port, me.getValue()); //System.out.println("sending announce to ID:"+e.getID()+" addr:"+e.getAddress()); anr.setDestination(e.getAddress()); anr.setSeed(isSeed); if(!rpcCall(anr,e.getID(),c -> { c.builtFromEntry(e); todo.entrySet().remove(me); })) { break; } } } @Override public int getTodoCount() { return todo.size(); } @Override boolean canDoRequest() { // a) we only announce to K nodes, not N; b) wait out the full timeout, not he adaptive one return getNumOutstandingRequests() < DHTConstants.MAX_ENTRIES_PER_BUCKET; } @Override protected boolean isDone() { if(getRecvResponses() >= DHTConstants.MAX_ENTRIES_PER_BUCKET) return true; if(todo.isEmpty() && getNumOutstandingRequests() == 0) return true; return false; } /** * @return the info_hash */ public Key getInfoHash () { return targetKey; } /* (non-Javadoc) * @see lbms.plugins.mldht.kad.Task#start() */ @Override public void start () { super.start(); } }