package net.i2p.client.streaming.impl;
import net.i2p.I2PAppContext;
/**
* <p>Scheduler used for after our SYN has been sent and ACKed but one
* (or more) sides haven't closed the stream yet. In addition, the
* stream must be using the BULK profile, rather than the INTERACTIVE
* profile.</p>
*
* <h2>Entry conditions:</h2>
* <ul>
* <li>Packets sent and ACKs received.</li>
* <li>At least one direction is not closed</li>
* </ul>
*
* <h2>Events:</h2>
* <ul>
* <li>Packets received (which may or may not ACK the ones sent)</li>
* <li>Message flush (explicitly, through a full buffer, or stream closure)</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 SchedulerClosing closing} - after both sending and receiving a CLOSE</li>
* <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 SchedulerConnectedBulk extends SchedulerImpl {
public SchedulerConnectedBulk(I2PAppContext ctx) {
super(ctx);
}
public boolean accept(Connection con) {
boolean ok = (con != null) &&
(con.getHighestAckedThrough() >= 0) &&
(con.getOptions().getProfile() == ConnectionOptions.PROFILE_BULK) &&
(!con.getResetReceived()) &&
( (con.getCloseSentOn() <= 0) || (con.getCloseReceivedOn() <= 0) );
if (!ok) {
//if (_log.shouldLog(Log.DEBUG))
// _log.debug("con: " + con + " closeSentOn: " + con.getCloseSentOn()
// + " closeReceivedOn: " + con.getCloseReceivedOn());
}
return ok;
}
public void eventOccurred(Connection con) {
if (con.getNextSendTime() <= 0)
return;
long timeTillSend = con.getNextSendTime() - _context.clock().now();
if (timeTillSend <= 0) {
con.setNextSendTime(-1);
con.sendAvailable();
} else {
reschedule(timeTillSend, con);
}
}
}