package net.i2p.client.streaming.impl;
import net.i2p.I2PAppContext;
import net.i2p.util.Log;
/**
* <p>Scheduler used for after both SYNs have been ACKed and both sides
* have closed the stream, but either we haven't ACKed their close or
* they haven't ACKed ours.</p>
*
* <h2>Entry conditions:</h2>
* <ul>
* <li>Both sides have closed.</li>
* <li>At least one direction has not ACKed the close.</li>
* </ul>
*
* <h2>Events:</h2>
* <ul>
* <li>Packets received (which may or may not ACK the ones sent)</li>
* <li>RESET received</li>
* <li>Message sending fails (error talking to the session)</li>
* <li>Message sending fails (too many resends)</li>
* </ul>
*
* <h2>Next states:</h2>
* <ul>
* <li>{@link SchedulerClosed closed} - after both sending and receiving ACKs on the CLOSE</li>
* <li>{@link SchedulerDead dead} - after sending or receiving a RESET</li>
* </ul>
*
*/
class SchedulerClosing extends SchedulerImpl {
public SchedulerClosing(I2PAppContext ctx) {
super(ctx);
}
public boolean accept(Connection con) {
if (con == null)
return false;
long timeSinceClose = _context.clock().now() - con.getCloseSentOn();
boolean ok = (!con.getResetSent()) &&
(!con.getResetReceived()) &&
( (con.getCloseSentOn() > 0) || (con.getCloseReceivedOn() > 0) ) &&
(timeSinceClose < Connection.DISCONNECT_TIMEOUT) &&
( (con.getUnackedPacketsReceived() > 0) || (con.getUnackedPacketsSent() > 0) );
return ok;
}
public void eventOccurred(Connection con) {
long nextSend = con.getNextSendTime();
long now = _context.clock().now();
long remaining;
if (nextSend <= 0) {
remaining = con.getOptions().getSendAckDelay();
nextSend = now + remaining;
con.setNextSendTime(nextSend);
} else {
remaining = nextSend - now;
}
if (_log.shouldLog(Log.DEBUG))
_log.debug("Event occurred w/ remaining: " + remaining + " on " + con);
if (remaining <= 0) {
if (con.getCloseSentOn() <= 0) {
con.sendAvailable();
} else {
//con.ackImmediately();
}
con.setNextSendTime(now + con.getOptions().getSendAckDelay());
} else {
//if (remaining < 5*1000)
// remaining = 5*1000;
//con.setNextSendTime(when
reschedule(remaining, con);
}
}
}