2005-10-19 22:02:37 +00:00
|
|
|
/* PeerConnectionOut - Keeps a queue of outgoing messages and delivers them.
|
|
|
|
Copyright (C) 2003 Mark J. Wielaard
|
|
|
|
|
|
|
|
This file is part of Snark.
|
|
|
|
|
|
|
|
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, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package org.klomp.snark;
|
|
|
|
|
2008-07-16 13:42:54 +00:00
|
|
|
import java.io.DataOutputStream;
|
|
|
|
import java.io.IOException;
|
2017-12-07 19:44:56 +00:00
|
|
|
import java.util.Arrays;
|
2008-07-16 13:42:54 +00:00
|
|
|
import java.util.Iterator;
|
|
|
|
import java.util.List;
|
2015-05-19 23:21:18 +00:00
|
|
|
import java.util.concurrent.BlockingQueue;
|
|
|
|
import java.util.concurrent.LinkedBlockingQueue;
|
2013-11-17 15:03:10 +00:00
|
|
|
import java.util.concurrent.atomic.AtomicLong;
|
2005-10-19 22:02:37 +00:00
|
|
|
|
2010-04-12 19:07:53 +00:00
|
|
|
import net.i2p.I2PAppContext;
|
2008-11-16 17:24:08 +00:00
|
|
|
import net.i2p.util.I2PAppThread;
|
2005-12-16 03:00:48 +00:00
|
|
|
import net.i2p.util.Log;
|
2011-01-10 17:49:00 +00:00
|
|
|
//import net.i2p.util.SimpleTimer;
|
2005-12-16 03:00:48 +00:00
|
|
|
|
2005-10-19 22:02:37 +00:00
|
|
|
class PeerConnectionOut implements Runnable
|
|
|
|
{
|
2010-04-12 19:07:53 +00:00
|
|
|
private final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(PeerConnectionOut.class);
|
2005-10-19 22:02:37 +00:00
|
|
|
private final Peer peer;
|
|
|
|
private final DataOutputStream dout;
|
|
|
|
|
|
|
|
private Thread thread;
|
|
|
|
private boolean quit;
|
|
|
|
|
|
|
|
// Contains Messages.
|
2015-05-19 23:21:18 +00:00
|
|
|
private final BlockingQueue<Message> sendQueue = new LinkedBlockingQueue<Message>();
|
2005-12-16 03:00:48 +00:00
|
|
|
|
2013-11-17 15:03:10 +00:00
|
|
|
private static final AtomicLong __id = new AtomicLong();
|
|
|
|
private final long _id;
|
2005-12-19 13:34:52 +00:00
|
|
|
|
|
|
|
long lastSent;
|
2005-10-19 22:02:37 +00:00
|
|
|
|
|
|
|
public PeerConnectionOut(Peer peer, DataOutputStream dout)
|
|
|
|
{
|
|
|
|
this.peer = peer;
|
|
|
|
this.dout = dout;
|
2013-11-17 15:03:10 +00:00
|
|
|
_id = __id.incrementAndGet();
|
2005-10-19 22:02:37 +00:00
|
|
|
|
2005-12-19 13:34:52 +00:00
|
|
|
lastSent = System.currentTimeMillis();
|
2005-12-20 02:01:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void startup() {
|
2008-11-16 17:24:08 +00:00
|
|
|
thread = new I2PAppThread(this, "Snark sender " + _id + ": " + peer);
|
2005-10-19 22:02:37 +00:00
|
|
|
thread.start();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Continuesly monitors for more outgoing messages that have to be send.
|
2013-10-12 17:39:49 +00:00
|
|
|
* Stops if quit is true or an IOException occurs.
|
2005-10-19 22:02:37 +00:00
|
|
|
*/
|
|
|
|
public void run()
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2024-01-15 10:05:46 +00:00
|
|
|
boolean shouldThrottleRequests = false;
|
2005-12-18 05:39:52 +00:00
|
|
|
while (!quit && peer.isConnected())
|
2005-10-19 22:02:37 +00:00
|
|
|
{
|
|
|
|
Message m = null;
|
|
|
|
PeerState state = null;
|
2007-01-29 04:03:36 +00:00
|
|
|
boolean shouldFlush;
|
|
|
|
synchronized(sendQueue)
|
|
|
|
{
|
|
|
|
shouldFlush = !quit && peer.isConnected() && sendQueue.isEmpty();
|
|
|
|
}
|
|
|
|
if (shouldFlush)
|
|
|
|
// Make sure everything will reach the other side.
|
|
|
|
// flush while not holding lock, could take a long time
|
|
|
|
dout.flush();
|
|
|
|
|
2005-10-19 22:02:37 +00:00
|
|
|
synchronized(sendQueue)
|
|
|
|
{
|
2024-01-15 10:05:46 +00:00
|
|
|
while (!quit && peer.isConnected() && (shouldThrottleRequests || sendQueue.isEmpty()))
|
2005-10-19 22:02:37 +00:00
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// Make sure everything will reach the other side.
|
2007-01-29 04:03:36 +00:00
|
|
|
// don't flush while holding lock, could take a long time
|
|
|
|
// dout.flush();
|
2005-10-19 22:02:37 +00:00
|
|
|
|
|
|
|
// Wait till more data arrives.
|
2024-01-15 10:05:46 +00:00
|
|
|
sendQueue.wait(shouldThrottleRequests ? 5000 : 60*1000);
|
2005-10-19 22:02:37 +00:00
|
|
|
}
|
|
|
|
catch (InterruptedException ie)
|
|
|
|
{
|
|
|
|
/* ignored */
|
|
|
|
}
|
2024-01-15 10:05:46 +00:00
|
|
|
shouldThrottleRequests = false;
|
2005-10-19 22:02:37 +00:00
|
|
|
}
|
|
|
|
state = peer.state;
|
2005-12-18 05:39:52 +00:00
|
|
|
if (!quit && state != null && peer.isConnected())
|
2005-10-19 22:02:37 +00:00
|
|
|
{
|
|
|
|
// Piece messages are big. So if there are other
|
|
|
|
// (control) messages make sure they are send first.
|
|
|
|
// Also remove request messages from the queue if
|
|
|
|
// we are currently being choked to prevent them from
|
|
|
|
// being send even if we get unchoked a little later.
|
|
|
|
// (Since we will resent them anyway in that case.)
|
|
|
|
// And remove piece messages if we are choking.
|
2005-12-17 03:47:02 +00:00
|
|
|
|
|
|
|
// this should get fixed for starvation
|
2013-11-21 12:43:45 +00:00
|
|
|
Iterator<Message> it = sendQueue.iterator();
|
2005-10-19 22:02:37 +00:00
|
|
|
while (m == null && it.hasNext())
|
|
|
|
{
|
2013-11-21 12:43:45 +00:00
|
|
|
Message nm = it.next();
|
2005-10-19 22:02:37 +00:00
|
|
|
if (nm.type == Message.PIECE)
|
|
|
|
{
|
2005-12-19 13:34:52 +00:00
|
|
|
if (state.choking) {
|
2005-10-19 22:02:37 +00:00
|
|
|
it.remove();
|
2015-05-19 23:21:18 +00:00
|
|
|
if (peer.supportsFast()) {
|
2017-08-22 12:34:38 +00:00
|
|
|
Message r = new Message(Message.REJECT, nm.piece, nm.begin, nm.length);
|
2015-05-19 23:21:18 +00:00
|
|
|
if (_log.shouldLog(Log.DEBUG))
|
|
|
|
_log.debug("Send " + peer + ": " + r);
|
|
|
|
r.sendMessage(dout);
|
|
|
|
}
|
2005-12-19 13:34:52 +00:00
|
|
|
}
|
2005-10-19 22:02:37 +00:00
|
|
|
nm = null;
|
|
|
|
}
|
2024-01-15 10:05:46 +00:00
|
|
|
else if (nm.type == Message.REQUEST)
|
2005-10-19 22:02:37 +00:00
|
|
|
{
|
2024-01-15 10:05:46 +00:00
|
|
|
if (state.choked) {
|
|
|
|
it.remove();
|
|
|
|
nm = null;
|
|
|
|
} else if (shouldThrottleRequests) {
|
|
|
|
// previous request in queue throttled, skip this one too
|
|
|
|
if (_log.shouldWarn())
|
|
|
|
_log.warn("Additional throttle: " + nm + " to " + peer);
|
|
|
|
nm = null;
|
|
|
|
} else if (!peer.shouldRequest(nm.length)) {
|
|
|
|
// request throttle, skip this and all others in this loop
|
|
|
|
if (_log.shouldWarn())
|
|
|
|
_log.warn("Throttle: " + nm + " to " + peer);
|
|
|
|
shouldThrottleRequests = true;
|
|
|
|
nm = null;
|
|
|
|
}
|
2005-10-19 22:02:37 +00:00
|
|
|
}
|
|
|
|
|
2014-04-21 10:54:52 +00:00
|
|
|
if (nm != null)
|
2005-10-19 22:02:37 +00:00
|
|
|
{
|
|
|
|
m = nm;
|
|
|
|
it.remove();
|
|
|
|
}
|
|
|
|
}
|
2015-05-19 23:21:18 +00:00
|
|
|
if (m == null) {
|
2024-01-15 10:05:46 +00:00
|
|
|
m = sendQueue.peek();
|
|
|
|
if (m != null && m.type == Message.PIECE) {
|
|
|
|
// bandwidth limiting
|
|
|
|
// Pieces are the last thing in the queue to be sent so we can
|
|
|
|
// simply wait right here and then loop
|
|
|
|
if (!peer.shouldSend(Math.min(m.length, PeerState.PARTSIZE))) {
|
|
|
|
if (_log.shouldWarn())
|
|
|
|
_log.warn("Throttle: " + m + " to " + peer);
|
|
|
|
try {
|
|
|
|
sendQueue.wait(5000);
|
|
|
|
} catch (InterruptedException ie) {}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else if (m != null && m.type == Message.REQUEST) {
|
|
|
|
if (shouldThrottleRequests)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
m = sendQueue.poll();
|
2005-12-19 13:34:52 +00:00
|
|
|
}
|
2005-10-19 22:02:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (m != null)
|
|
|
|
{
|
2005-12-16 03:00:48 +00:00
|
|
|
if (_log.shouldLog(Log.DEBUG))
|
2010-12-21 03:04:10 +00:00
|
|
|
_log.debug("Send " + peer + ": " + m);
|
2010-03-08 00:45:08 +00:00
|
|
|
|
|
|
|
// This can block for quite a while.
|
|
|
|
// To help get slow peers going, and track the bandwidth better,
|
|
|
|
// move this _after_ state.uploaded() and see how it works.
|
|
|
|
//m.sendMessage(dout);
|
2005-12-19 13:34:52 +00:00
|
|
|
lastSent = System.currentTimeMillis();
|
2005-10-19 22:02:37 +00:00
|
|
|
|
|
|
|
// Remove all piece messages after sending a choke message.
|
2015-08-24 17:30:32 +00:00
|
|
|
// FiXME this causes REJECT messages to be sent before sending the CHOKE;
|
|
|
|
// BEP 6 recommends sending them after.
|
2005-10-19 22:02:37 +00:00
|
|
|
if (m.type == Message.CHOKE)
|
|
|
|
removeMessage(Message.PIECE);
|
|
|
|
|
|
|
|
// XXX - Should also register overhead...
|
2010-03-16 13:32:34 +00:00
|
|
|
// Don't let other clients requesting big chunks get an advantage
|
|
|
|
// when we are seeding;
|
|
|
|
// only count the rest of the upload after sendMessage().
|
|
|
|
int remainder = 0;
|
|
|
|
if (m.type == Message.PIECE) {
|
2024-01-15 10:05:46 +00:00
|
|
|
// first PARTSIZE was signalled in shouldSend() above
|
|
|
|
if (m.len > PeerState.PARTSIZE)
|
2010-03-16 13:32:34 +00:00
|
|
|
remainder = m.len - PeerState.PARTSIZE;
|
|
|
|
}
|
2005-10-19 22:02:37 +00:00
|
|
|
|
2010-03-08 00:45:08 +00:00
|
|
|
m.sendMessage(dout);
|
2010-03-16 13:32:34 +00:00
|
|
|
if (remainder > 0)
|
2024-01-15 10:05:46 +00:00
|
|
|
peer.uploaded(remainder);
|
2005-10-19 22:02:37 +00:00
|
|
|
m = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (IOException ioe)
|
|
|
|
{
|
|
|
|
// Ignore, probably other side closed connection.
|
2005-12-19 13:34:52 +00:00
|
|
|
if (_log.shouldLog(Log.INFO))
|
|
|
|
_log.info("IOError sending to " + peer, ioe);
|
2005-10-19 22:02:37 +00:00
|
|
|
}
|
|
|
|
catch (Throwable t)
|
|
|
|
{
|
2005-12-19 13:34:52 +00:00
|
|
|
_log.error("Error sending to " + peer, t);
|
2005-12-18 05:39:52 +00:00
|
|
|
if (t instanceof OutOfMemoryError)
|
|
|
|
throw (OutOfMemoryError)t;
|
2005-10-19 22:02:37 +00:00
|
|
|
}
|
|
|
|
finally
|
|
|
|
{
|
|
|
|
quit = true;
|
|
|
|
peer.disconnect();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void disconnect()
|
|
|
|
{
|
|
|
|
synchronized(sendQueue)
|
|
|
|
{
|
2005-12-19 13:34:52 +00:00
|
|
|
//if (quit == true)
|
|
|
|
// return;
|
2005-10-19 22:02:37 +00:00
|
|
|
|
|
|
|
quit = true;
|
2005-12-20 02:29:09 +00:00
|
|
|
if (thread != null)
|
|
|
|
thread.interrupt();
|
2005-10-19 22:02:37 +00:00
|
|
|
|
|
|
|
sendQueue.clear();
|
2013-10-12 17:39:49 +00:00
|
|
|
sendQueue.notifyAll();
|
2005-10-19 22:02:37 +00:00
|
|
|
}
|
2005-12-21 12:04:54 +00:00
|
|
|
if (dout != null) {
|
|
|
|
try {
|
|
|
|
dout.close();
|
|
|
|
} catch (IOException ioe) {
|
2013-10-12 17:39:49 +00:00
|
|
|
//_log.warn("Error closing the stream to " + peer, ioe);
|
2005-12-21 12:04:54 +00:00
|
|
|
}
|
|
|
|
}
|
2005-10-19 22:02:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Adds a message to the sendQueue and notifies the method waiting
|
|
|
|
* on the sendQueue to change.
|
|
|
|
*/
|
|
|
|
private void addMessage(Message m)
|
|
|
|
{
|
|
|
|
synchronized(sendQueue)
|
|
|
|
{
|
2015-05-19 23:21:18 +00:00
|
|
|
sendQueue.offer(m);
|
2005-12-17 03:47:02 +00:00
|
|
|
sendQueue.notifyAll();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-12-22 10:04:12 +00:00
|
|
|
/** remove messages not sent in 3m */
|
|
|
|
private static final int SEND_TIMEOUT = 3*60*1000;
|
2011-01-10 17:49:00 +00:00
|
|
|
|
|
|
|
/*****
|
2005-12-17 03:47:02 +00:00
|
|
|
private class RemoveTooSlow implements SimpleTimer.TimedEvent {
|
|
|
|
private Message _m;
|
|
|
|
public RemoveTooSlow(Message m) {
|
|
|
|
_m = m;
|
2005-12-19 13:34:52 +00:00
|
|
|
m.expireEvent = RemoveTooSlow.this;
|
2005-12-17 03:47:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void timeReached() {
|
|
|
|
boolean removed = false;
|
|
|
|
synchronized (sendQueue) {
|
|
|
|
removed = sendQueue.remove(_m);
|
|
|
|
sendQueue.notifyAll();
|
|
|
|
}
|
|
|
|
if (removed)
|
|
|
|
_log.info("Took too long to send " + _m + " to " + peer);
|
2005-10-19 22:02:37 +00:00
|
|
|
}
|
|
|
|
}
|
2011-01-10 17:49:00 +00:00
|
|
|
*****/
|
2005-10-19 22:02:37 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Removes a particular message type from the queue.
|
|
|
|
*
|
|
|
|
* @param type the Message type to remove.
|
|
|
|
* @returns true when a message of the given type was removed, false
|
|
|
|
* otherwise.
|
|
|
|
*/
|
|
|
|
private boolean removeMessage(int type)
|
|
|
|
{
|
|
|
|
boolean removed = false;
|
|
|
|
synchronized(sendQueue)
|
|
|
|
{
|
2013-11-21 12:43:45 +00:00
|
|
|
Iterator<Message> it = sendQueue.iterator();
|
2005-10-19 22:02:37 +00:00
|
|
|
while (it.hasNext())
|
|
|
|
{
|
2013-11-21 12:43:45 +00:00
|
|
|
Message m = it.next();
|
2015-05-19 18:13:32 +00:00
|
|
|
if (m.type == type) {
|
2005-10-19 22:02:37 +00:00
|
|
|
it.remove();
|
|
|
|
removed = true;
|
2015-05-19 18:13:32 +00:00
|
|
|
if (type == Message.PIECE && peer.supportsFast()) {
|
2017-08-22 12:34:38 +00:00
|
|
|
Message r = new Message(Message.REJECT, m.piece, m.begin, m.length);
|
2015-05-19 21:56:21 +00:00
|
|
|
if (_log.shouldLog(Log.DEBUG))
|
|
|
|
_log.debug("Send " + peer + ": " + r);
|
2015-05-19 18:13:32 +00:00
|
|
|
try {
|
|
|
|
r.sendMessage(dout);
|
|
|
|
} catch (IOException ioe) {}
|
|
|
|
}
|
|
|
|
}
|
2005-10-19 22:02:37 +00:00
|
|
|
}
|
2005-12-17 03:47:02 +00:00
|
|
|
sendQueue.notifyAll();
|
2005-10-19 22:02:37 +00:00
|
|
|
}
|
|
|
|
return removed;
|
|
|
|
}
|
|
|
|
|
|
|
|
void sendAlive()
|
|
|
|
{
|
2006-09-06 06:32:53 +00:00
|
|
|
synchronized(sendQueue)
|
|
|
|
{
|
2017-08-22 12:34:38 +00:00
|
|
|
if(sendQueue.isEmpty()) {
|
|
|
|
Message m = new Message(Message.KEEP_ALIVE);
|
2015-05-19 23:21:18 +00:00
|
|
|
sendQueue.offer(m);
|
2017-08-22 12:34:38 +00:00
|
|
|
}
|
2006-09-06 06:32:53 +00:00
|
|
|
sendQueue.notifyAll();
|
|
|
|
}
|
2005-10-19 22:02:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void sendChoke(boolean choke)
|
|
|
|
{
|
|
|
|
// We cancel the (un)choke but keep PIECE messages.
|
|
|
|
// PIECE messages are purged if a choke is actually send.
|
|
|
|
synchronized(sendQueue)
|
|
|
|
{
|
|
|
|
int inverseType = choke ? Message.UNCHOKE
|
|
|
|
: Message.CHOKE;
|
|
|
|
if (!removeMessage(inverseType))
|
|
|
|
{
|
2017-08-22 12:34:38 +00:00
|
|
|
Message m = new Message(choke ? Message.CHOKE : Message.UNCHOKE);
|
2005-10-19 22:02:37 +00:00
|
|
|
addMessage(m);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void sendInterest(boolean interest)
|
|
|
|
{
|
|
|
|
synchronized(sendQueue)
|
|
|
|
{
|
|
|
|
int inverseType = interest ? Message.UNINTERESTED
|
|
|
|
: Message.INTERESTED;
|
|
|
|
if (!removeMessage(inverseType))
|
|
|
|
{
|
2017-08-22 12:34:38 +00:00
|
|
|
Message m = new Message(interest ? Message.INTERESTED : Message.UNINTERESTED);
|
2005-10-19 22:02:37 +00:00
|
|
|
addMessage(m);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void sendHave(int piece)
|
|
|
|
{
|
2017-08-22 12:34:38 +00:00
|
|
|
Message m = new Message(Message.HAVE, piece);
|
2005-10-19 22:02:37 +00:00
|
|
|
addMessage(m);
|
|
|
|
}
|
|
|
|
|
|
|
|
void sendBitfield(BitField bitfield)
|
|
|
|
{
|
2015-05-19 18:13:32 +00:00
|
|
|
boolean fast = peer.supportsFast();
|
2017-12-07 19:44:56 +00:00
|
|
|
boolean all = false;
|
|
|
|
boolean none = false;
|
|
|
|
byte[] data = null;
|
|
|
|
synchronized(bitfield) {
|
|
|
|
if (fast && bitfield.complete()) {
|
|
|
|
all = true;
|
|
|
|
} else if (fast && bitfield.count() <= 0) {
|
|
|
|
none = true;
|
|
|
|
} else {
|
|
|
|
byte[] d = bitfield.getFieldBytes();
|
|
|
|
data = Arrays.copyOf(d, d.length);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (all) {
|
2015-05-19 18:13:32 +00:00
|
|
|
sendHaveAll();
|
2017-12-07 19:44:56 +00:00
|
|
|
} else if (none) {
|
2015-05-19 18:13:32 +00:00
|
|
|
sendHaveNone();
|
|
|
|
} else {
|
2017-12-07 19:44:56 +00:00
|
|
|
Message m = new Message(data);
|
2015-05-19 18:13:32 +00:00
|
|
|
addMessage(m);
|
|
|
|
}
|
2005-10-19 22:02:37 +00:00
|
|
|
}
|
|
|
|
|
2006-09-16 21:07:28 +00:00
|
|
|
/** reransmit requests not received in 7m */
|
|
|
|
private static final int REQ_TIMEOUT = (2 * SEND_TIMEOUT) + (60 * 1000);
|
2013-11-21 12:43:45 +00:00
|
|
|
void retransmitRequests(List<Request> requests)
|
2006-09-16 21:07:28 +00:00
|
|
|
{
|
|
|
|
long now = System.currentTimeMillis();
|
2013-11-21 12:43:45 +00:00
|
|
|
Iterator<Request> it = requests.iterator();
|
2006-09-16 21:07:28 +00:00
|
|
|
while (it.hasNext())
|
|
|
|
{
|
2013-11-21 12:43:45 +00:00
|
|
|
Request req = it.next();
|
2006-09-16 21:07:28 +00:00
|
|
|
if(now > req.sendTime + REQ_TIMEOUT) {
|
|
|
|
if (_log.shouldLog(Log.DEBUG))
|
|
|
|
_log.debug("Retransmit request " + req + " to peer " + peer);
|
|
|
|
sendRequest(req);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-21 12:43:45 +00:00
|
|
|
void sendRequests(List<Request> requests)
|
2005-10-19 22:02:37 +00:00
|
|
|
{
|
2013-11-21 12:43:45 +00:00
|
|
|
Iterator<Request> it = requests.iterator();
|
2005-10-19 22:02:37 +00:00
|
|
|
while (it.hasNext())
|
|
|
|
{
|
2013-11-21 12:43:45 +00:00
|
|
|
Request req = it.next();
|
2005-10-19 22:02:37 +00:00
|
|
|
sendRequest(req);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void sendRequest(Request req)
|
|
|
|
{
|
2006-09-20 22:39:24 +00:00
|
|
|
// Check for duplicate requests to deal with fibrillating i2p-bt
|
|
|
|
// (multiple choke/unchokes received cause duplicate requests in the queue)
|
|
|
|
synchronized(sendQueue)
|
|
|
|
{
|
2013-11-21 12:43:45 +00:00
|
|
|
Iterator<Message> it = sendQueue.iterator();
|
2006-09-20 22:39:24 +00:00
|
|
|
while (it.hasNext())
|
|
|
|
{
|
2013-11-21 12:43:45 +00:00
|
|
|
Message m = it.next();
|
2012-05-19 13:27:02 +00:00
|
|
|
if (m.type == Message.REQUEST && m.piece == req.getPiece() &&
|
2006-09-20 22:39:24 +00:00
|
|
|
m.begin == req.off && m.length == req.len)
|
|
|
|
{
|
|
|
|
if (_log.shouldLog(Log.DEBUG))
|
|
|
|
_log.debug("Discarding duplicate request " + req + " to peer " + peer);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-08-22 12:34:38 +00:00
|
|
|
Message m = new Message(Message.REQUEST, req.getPiece(), req.off, req.len);
|
2005-10-19 22:02:37 +00:00
|
|
|
addMessage(m);
|
2006-09-16 21:07:28 +00:00
|
|
|
req.sendTime = System.currentTimeMillis();
|
2005-10-19 22:02:37 +00:00
|
|
|
}
|
|
|
|
|
2008-05-18 21:45:54 +00:00
|
|
|
// Used by PeerState to limit pipelined requests
|
|
|
|
int queuedBytes()
|
|
|
|
{
|
|
|
|
int total = 0;
|
|
|
|
synchronized(sendQueue)
|
|
|
|
{
|
2013-11-21 12:43:45 +00:00
|
|
|
Iterator<Message> it = sendQueue.iterator();
|
2008-05-18 21:45:54 +00:00
|
|
|
while (it.hasNext())
|
|
|
|
{
|
2013-11-21 12:43:45 +00:00
|
|
|
Message m = it.next();
|
2008-05-18 21:45:54 +00:00
|
|
|
if (m.type == Message.PIECE)
|
|
|
|
total += m.length;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return total;
|
|
|
|
}
|
|
|
|
|
2010-11-29 13:08:03 +00:00
|
|
|
/**
|
|
|
|
* Queue a piece message with a callback to load the data
|
|
|
|
* from disk when required.
|
|
|
|
* @since 0.8.2
|
|
|
|
*/
|
2010-11-21 21:19:12 +00:00
|
|
|
void sendPiece(int piece, int begin, int length, DataLoader loader)
|
|
|
|
{
|
2012-09-17 21:32:05 +00:00
|
|
|
/****
|
2010-11-21 21:19:12 +00:00
|
|
|
boolean sendNow = false;
|
|
|
|
// are there any cases where we should?
|
|
|
|
|
|
|
|
if (sendNow) {
|
|
|
|
// queue the real thing
|
|
|
|
byte[] bytes = loader.loadData(piece, begin, length);
|
|
|
|
if (bytes != null)
|
|
|
|
sendPiece(piece, begin, length, bytes);
|
|
|
|
return;
|
|
|
|
}
|
2012-09-17 21:32:05 +00:00
|
|
|
****/
|
2010-11-21 21:19:12 +00:00
|
|
|
|
|
|
|
// queue a fake message... set everything up,
|
|
|
|
// except save the PeerState instead of the bytes.
|
2017-08-22 12:34:38 +00:00
|
|
|
Message m = new Message(piece, begin, length, loader);
|
2010-11-21 21:19:12 +00:00
|
|
|
addMessage(m);
|
|
|
|
}
|
|
|
|
|
2010-11-29 13:08:03 +00:00
|
|
|
/**
|
|
|
|
* Queue a piece message with the data already loaded from disk
|
|
|
|
* Also add a timeout.
|
|
|
|
* We don't use this anymore.
|
|
|
|
*/
|
2017-08-22 12:34:38 +00:00
|
|
|
/****
|
2005-10-19 22:02:37 +00:00
|
|
|
void sendPiece(int piece, int begin, int length, byte[] bytes)
|
|
|
|
{
|
2017-08-22 12:34:38 +00:00
|
|
|
Message m = new Message(piece, begin, length, bytes);
|
2010-11-29 13:08:03 +00:00
|
|
|
// since we have the data already loaded, queue a timeout to remove it
|
2011-01-10 17:49:00 +00:00
|
|
|
// no longer prefetched
|
2005-10-19 22:02:37 +00:00
|
|
|
addMessage(m);
|
|
|
|
}
|
2017-08-22 12:34:38 +00:00
|
|
|
****/
|
2005-10-19 22:02:37 +00:00
|
|
|
|
2017-08-22 12:34:38 +00:00
|
|
|
/** send cancel */
|
2005-10-19 22:02:37 +00:00
|
|
|
void sendCancel(Request req)
|
|
|
|
{
|
|
|
|
// See if it is still in our send queue
|
|
|
|
synchronized(sendQueue)
|
|
|
|
{
|
2013-11-21 12:43:45 +00:00
|
|
|
Iterator<Message> it = sendQueue.iterator();
|
2005-10-19 22:02:37 +00:00
|
|
|
while (it.hasNext())
|
|
|
|
{
|
2013-11-21 12:43:45 +00:00
|
|
|
Message m = it.next();
|
2005-10-19 22:02:37 +00:00
|
|
|
if (m.type == Message.REQUEST
|
2012-05-19 13:27:02 +00:00
|
|
|
&& m.piece == req.getPiece()
|
2005-10-19 22:02:37 +00:00
|
|
|
&& m.begin == req.off
|
|
|
|
&& m.length == req.len)
|
|
|
|
it.remove();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Always send, just to be sure it it is really canceled.
|
2017-08-22 12:34:38 +00:00
|
|
|
Message m = new Message(Message.CANCEL, req.getPiece(), req.off, req.len);
|
2005-10-19 22:02:37 +00:00
|
|
|
addMessage(m);
|
|
|
|
}
|
|
|
|
|
2010-11-27 14:34:08 +00:00
|
|
|
/**
|
2015-05-19 21:56:21 +00:00
|
|
|
* Remove all Request messages from the queue.
|
|
|
|
* Does not send a cancel message.
|
2010-11-27 14:34:08 +00:00
|
|
|
* @since 0.8.2
|
|
|
|
*/
|
|
|
|
void cancelRequestMessages() {
|
|
|
|
synchronized(sendQueue) {
|
|
|
|
for (Iterator<Message> it = sendQueue.iterator(); it.hasNext(); ) {
|
|
|
|
if (it.next().type == Message.REQUEST)
|
|
|
|
it.remove();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-19 21:56:21 +00:00
|
|
|
/**
|
|
|
|
* Called by the PeerState when the other side doesn't want this
|
|
|
|
* request to be handled anymore. Removes any pending Piece Message
|
|
|
|
* from out send queue.
|
|
|
|
* Does not send a cancel message.
|
|
|
|
*/
|
2005-10-19 22:02:37 +00:00
|
|
|
void cancelRequest(int piece, int begin, int length)
|
|
|
|
{
|
|
|
|
synchronized (sendQueue)
|
|
|
|
{
|
2013-11-21 12:43:45 +00:00
|
|
|
Iterator<Message> it = sendQueue.iterator();
|
2005-10-19 22:02:37 +00:00
|
|
|
while (it.hasNext())
|
|
|
|
{
|
2013-11-21 12:43:45 +00:00
|
|
|
Message m = it.next();
|
2005-10-19 22:02:37 +00:00
|
|
|
if (m.type == Message.PIECE
|
|
|
|
&& m.piece == piece
|
|
|
|
&& m.begin == begin
|
|
|
|
&& m.length == length)
|
|
|
|
it.remove();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-11-21 21:19:12 +00:00
|
|
|
|
|
|
|
/** @since 0.8.2 */
|
|
|
|
void sendExtension(int id, byte[] bytes) {
|
2017-08-22 12:34:38 +00:00
|
|
|
Message m = new Message(id, bytes);
|
2010-11-21 21:19:12 +00:00
|
|
|
addMessage(m);
|
|
|
|
}
|
2010-12-19 15:37:11 +00:00
|
|
|
|
|
|
|
/** @since 0.8.4 */
|
|
|
|
void sendPort(int port) {
|
2017-08-22 12:34:38 +00:00
|
|
|
Message m = new Message(Message.PORT, port);
|
2010-12-19 15:37:11 +00:00
|
|
|
addMessage(m);
|
|
|
|
}
|
2015-05-19 18:13:32 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Unused
|
|
|
|
* @since 0.9.21
|
|
|
|
*/
|
2017-08-22 12:34:38 +00:00
|
|
|
/****
|
2015-05-19 18:13:32 +00:00
|
|
|
void sendSuggest(int piece) {
|
2017-08-22 12:34:38 +00:00
|
|
|
Message m = new Message(Message.SUGGEST, piece);
|
2015-05-19 18:13:32 +00:00
|
|
|
addMessage(m);
|
|
|
|
}
|
2017-08-22 12:34:38 +00:00
|
|
|
****/
|
2015-05-19 18:13:32 +00:00
|
|
|
|
|
|
|
/** @since 0.9.21 */
|
|
|
|
private void sendHaveAll() {
|
2017-08-22 12:34:38 +00:00
|
|
|
Message m = new Message(Message.HAVE_ALL);
|
2015-05-19 18:13:32 +00:00
|
|
|
addMessage(m);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @since 0.9.21 */
|
|
|
|
private void sendHaveNone() {
|
2017-08-22 12:34:38 +00:00
|
|
|
Message m = new Message(Message.HAVE_NONE);
|
2015-05-19 18:13:32 +00:00
|
|
|
addMessage(m);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @since 0.9.21 */
|
|
|
|
void sendReject(int piece, int begin, int length) {
|
2017-08-22 12:34:38 +00:00
|
|
|
Message m = new Message(Message.REJECT, piece, begin, length);
|
2015-05-19 18:13:32 +00:00
|
|
|
addMessage(m);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Unused
|
|
|
|
* @since 0.9.21
|
|
|
|
*/
|
2017-08-22 12:34:38 +00:00
|
|
|
/****
|
2015-05-19 18:13:32 +00:00
|
|
|
void sendAllowedFast(int piece) {
|
2017-08-22 12:34:38 +00:00
|
|
|
Message m = new Message(Message.ALLOWED_FAST, piece);
|
2015-05-19 18:13:32 +00:00
|
|
|
addMessage(m);
|
|
|
|
}
|
2017-08-22 12:34:38 +00:00
|
|
|
****/
|
2005-10-19 22:02:37 +00:00
|
|
|
}
|