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); } } }