use of net.i2p.client.streaming.I2PSocketException in project i2p.i2p by i2p.
the class PacketQueue method messageStatus.
/**
* SendMessageStatusListener interface
*
* Tell the client of an update in the send status for a message
* previously sent with I2PSession.sendMessage().
* Multiple calls for a single message ID are possible.
*
* @param session session notifying
* @param msgId message number returned from a previous sendMessage() call
* @param status of the message, as defined in MessageStatusMessage and this class.
* @since 0.9.14
*/
public void messageStatus(I2PSession session, long msgId, int status) {
if (_dead)
return;
Long id = Long.valueOf(msgId);
Connection con = _messageStatusMap.get(id);
if (con == null) {
if (_log.shouldLog(Log.WARN))
_log.warn("Rcvd status " + status + " for msg " + msgId + " on unknown connection");
return;
}
switch(status) {
case MessageStatusMessage.STATUS_SEND_BEST_EFFORT_FAILURE:
// not really guaranteed
case MessageStatusMessage.STATUS_SEND_GUARANTEED_FAILURE:
// no tunnels may fix itself, allow retx
case MessageStatusMessage.STATUS_SEND_FAILURE_NO_TUNNELS:
// probably took a long time to open the tunnel, allow retx
case MessageStatusMessage.STATUS_SEND_FAILURE_EXPIRED:
// overflow in router-side I2CP queue, sent as of 0.9.29, will be retried
case MessageStatusMessage.STATUS_SEND_FAILURE_LOCAL:
if (_log.shouldLog(Log.WARN))
_log.warn("Rcvd soft failure status " + status + " for msg " + msgId + " on " + con);
_messageStatusMap.remove(id);
break;
case MessageStatusMessage.STATUS_SEND_FAILURE_NO_LEASESET:
// Let the streaming retransmission paper over the problem.
if (_log.shouldLog(Log.WARN))
_log.warn("LS lookup (soft) failure for msg " + msgId + " on " + con);
_messageStatusMap.remove(id);
break;
case MessageStatusMessage.STATUS_SEND_FAILURE_ROUTER:
case MessageStatusMessage.STATUS_SEND_FAILURE_NETWORK:
case MessageStatusMessage.STATUS_SEND_FAILURE_BAD_SESSION:
case MessageStatusMessage.STATUS_SEND_FAILURE_BAD_MESSAGE:
case MessageStatusMessage.STATUS_SEND_FAILURE_BAD_OPTIONS:
case MessageStatusMessage.STATUS_SEND_FAILURE_OVERFLOW:
case MessageStatusMessage.STATUS_SEND_FAILURE_LOCAL_LEASESET:
case MessageStatusMessage.STATUS_SEND_FAILURE_UNSUPPORTED_ENCRYPTION:
case MessageStatusMessage.STATUS_SEND_FAILURE_DESTINATION:
case MessageStatusMessage.STATUS_SEND_FAILURE_BAD_LEASESET:
case MessageStatusMessage.STATUS_SEND_FAILURE_EXPIRED_LEASESET:
case SendMessageStatusListener.STATUS_CANCELLED:
if (con.getHighestAckedThrough() >= 0) {
// a retxed SYN succeeded before the first SYN failed
if (_log.shouldLog(Log.WARN))
_log.warn("Rcvd hard failure but already connected, status " + status + " for msg " + msgId + " on " + con);
} else if (!con.getIsConnected()) {
if (_log.shouldLog(Log.WARN))
_log.warn("Rcvd hard failure but already closed, status " + status + " for msg " + msgId + " on " + con);
} else {
if (_log.shouldLog(Log.WARN))
_log.warn("Rcvd hard failure status " + status + " for msg " + msgId + " on " + con);
_messageStatusMap.remove(id);
IOException ioe = new I2PSocketException(status);
con.getOutputStream().streamErrorOccurred(ioe);
con.getInputStream().streamErrorOccurred(ioe);
con.setConnectionError(ioe.getLocalizedMessage());
con.disconnect(false);
}
break;
case MessageStatusMessage.STATUS_SEND_BEST_EFFORT_SUCCESS:
case MessageStatusMessage.STATUS_SEND_GUARANTEED_SUCCESS:
case MessageStatusMessage.STATUS_SEND_SUCCESS_LOCAL:
if (_log.shouldLog(Log.INFO))
_log.info("Rcvd success status " + status + " for msg " + msgId + " on " + con);
_messageStatusMap.remove(id);
break;
case MessageStatusMessage.STATUS_SEND_ACCEPTED:
if (_log.shouldLog(Log.INFO))
_log.info("Rcvd accept status " + status + " for msg " + msgId + " on " + con);
break;
default:
if (_log.shouldLog(Log.WARN))
_log.warn("Rcvd unknown status " + status + " for msg " + msgId + " on " + con);
_messageStatusMap.remove(id);
break;
}
}
use of net.i2p.client.streaming.I2PSocketException in project i2p.i2p by i2p.
the class I2PTunnelRunner method run.
@Override
public void run() {
boolean i2pReset = false;
boolean sockReset = false;
InputStream in = null;
OutputStream out = null;
InputStream i2pin = null;
OutputStream i2pout = null;
StreamForwarder toI2P = null;
StreamForwarder fromI2P = null;
try {
in = getSocketIn();
// = new BufferedOutputStream(s.getOutputStream(), NETWORK_BUFFER_SIZE);
out = getSocketOut();
// unimplemented in streaming
// i2ps.setSocketErrorListener(this);
i2pin = i2ps.getInputStream();
// new BufferedOutputStream(i2ps.getOutputStream(), MAX_PACKET_SIZE);
i2pout = i2ps.getOutputStream();
if (initialI2PData != null) {
// why synchronize this? we could be in here a LONG time for large initial data
// synchronized (slock) {
// this does not increment totalSent
i2pout.write(initialI2PData);
// only flush if it fits in one message.
if (initialI2PData.length <= 1730) {
// Don't flush if POST, so we can get POST data into the initial packet
if (initialI2PData.length < 5 || !DataHelper.eq(POST, 0, initialI2PData, 0, 5))
i2pout.flush();
}
// }
}
if (initialSocketData != null) {
// this does not increment totalReceived
out.write(initialSocketData);
}
if (_log.shouldLog(Log.DEBUG))
_log.debug("Initial data " + (initialI2PData != null ? initialI2PData.length : 0) + " written to I2P, " + (initialSocketData != null ? initialSocketData.length : 0) + " written to the socket, starting forwarders");
if (!(s instanceof InternalSocket))
in = new BufferedInputStream(in, 2 * NETWORK_BUFFER_SIZE);
toI2P = new StreamForwarder(in, i2pout, true);
fromI2P = new StreamForwarder(i2pin, out, false);
toI2P.start();
// We are already a thread, so run the second one inline
// fromI2P.start();
fromI2P.run();
synchronized (finishLock) {
while (!finished) {
finishLock.wait();
}
}
if (_log.shouldLog(Log.DEBUG))
_log.debug("At least one forwarder completed, closing and joining");
// this task is useful for the httpclient
if ((onTimeout != null || _onFail != null) && totalReceived <= 0) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("runner has a timeout job, totalReceived = " + totalReceived + " totalSent = " + totalSent + " job = " + onTimeout);
// HTTPClient never sets initialSocketData.
if (_onFail != null) {
Exception e = fromI2P.getFailure();
if (e == null)
e = toI2P.getFailure();
_onFail.onFail(e);
} else {
onTimeout.run();
}
} else {
// Detect a reset on one side, and propagate to the other
Exception e1 = fromI2P.getFailure();
Exception e2 = toI2P.getFailure();
Throwable c1 = e1 != null ? e1.getCause() : null;
Throwable c2 = e2 != null ? e2.getCause() : null;
if (c1 != null && c1 instanceof I2PSocketException) {
I2PSocketException ise = (I2PSocketException) c1;
int status = ise.getStatus();
i2pReset = status == I2PSocketException.STATUS_CONNECTION_RESET;
}
if (!i2pReset && c2 != null && c2 instanceof I2PSocketException) {
I2PSocketException ise = (I2PSocketException) c2;
int status = ise.getStatus();
i2pReset = status == I2PSocketException.STATUS_CONNECTION_RESET;
}
if (!i2pReset && e1 != null && e1 instanceof SocketException) {
String msg = e1.getMessage();
sockReset = msg != null && msg.contains("reset");
}
if (!sockReset && e2 != null && e2 instanceof SocketException) {
String msg = e2.getMessage();
sockReset = msg != null && msg.contains("reset");
}
}
} catch (InterruptedException ex) {
if (_log.shouldLog(Log.ERROR))
_log.error("Interrupted", ex);
} catch (SSLException she) {
_log.error("SSL error", she);
} catch (IOException ex) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Error forwarding", ex);
} catch (IllegalStateException ise) {
// at net.i2p.i2ptunnel.I2PTunnelRunner.run(I2PTunnelRunner.java:167)
if (_log.shouldLog(Log.WARN))
_log.warn("gnu?", ise);
} catch (RuntimeException e) {
if (_log.shouldLog(Log.ERROR))
_log.error("Internal error", e);
} finally {
removeRef();
if (i2pReset) {
if (_log.shouldWarn())
_log.warn("Got I2P reset, resetting socket");
try {
s.setSoLinger(true, 0);
} catch (IOException ioe) {
}
try {
s.close();
} catch (IOException ioe) {
}
try {
i2ps.close();
} catch (IOException ioe) {
}
} else if (sockReset) {
if (_log.shouldWarn())
_log.warn("Got socket reset, resetting I2P socket");
try {
i2ps.reset();
} catch (IOException ioe) {
}
try {
s.close();
} catch (IOException ioe) {
}
} else {
// now one connection is dead - kill the other as well, after making sure we flush
try {
close(out, in, i2pout, i2pin, s, i2ps, toI2P, fromI2P);
} catch (InterruptedException ie) {
}
}
}
}
use of net.i2p.client.streaming.I2PSocketException in project i2p.i2p by i2p.
the class Connection method packetSendChoke.
/**
* This doesn't "send a choke". Rather, it blocks if the outbound window is full,
* thus choking the sender that calls this.
*
* Block until there is an open outbound packet slot or the write timeout
* expires.
* PacketLocal is the only caller, generally with -1.
*
* @param timeoutMs 0 or negative means wait forever, 5 minutes max
* @return true if the packet should be sent, false for a fatal error
* will return false after 5 minutes even if timeoutMs is <= 0.
*/
public boolean packetSendChoke(long timeoutMs) throws IOException, InterruptedException {
long start = _context.clock().now();
// only used if timeoutMs > 0
long writeExpire = start + timeoutMs;
boolean started = false;
while (true) {
long timeLeft = writeExpire - _context.clock().now();
synchronized (_outboundPackets) {
if (!started)
_context.statManager().addRateData("stream.chokeSizeBegin", _outboundPackets.size());
if (// ok, 5 minutes blocking? I dont think so
start + 5 * 60 * 1000 < _context.clock().now())
return false;
// Incorrect assumption, the constructor defaults _connected to true --Sponge
if (!_connected.get()) {
if (getResetReceived())
throw new I2PSocketException(I2PSocketException.STATUS_CONNECTION_RESET);
throw new IOException("Socket closed");
}
if (_outputStream.getClosed())
throw new IOException("Output stream closed");
started = true;
// Try to keep things moving even during NACKs and retransmissions...
// Limit unacked packets to the window
// Limit active resends to half the window
// Limit (highest-lowest) to twice the window (if far end doesn't like it, it can send a choke)
int unacked = _outboundPackets.size();
int wsz = _options.getWindowSize();
if (_isChoked || unacked >= wsz || _activeResends.get() >= (wsz + 1) / 2 || _lastSendId.get() - _highestAckedThrough >= Math.max(MAX_WINDOW_SIZE, 2 * wsz)) {
if (timeoutMs > 0) {
if (timeLeft <= 0) {
if (_log.shouldLog(Log.INFO))
_log.info("Outbound window is full (choked? " + _isChoked + ' ' + unacked + " unacked with " + _activeResends + " active resends" + " and we've waited too long (" + (0 - (timeLeft - timeoutMs)) + "ms): " + toString());
return false;
}
if (_log.shouldLog(Log.DEBUG))
_log.debug("Outbound window is full (choked? " + _isChoked + ' ' + unacked + '/' + wsz + '/' + _activeResends + "), waiting " + timeLeft);
try {
_outboundPackets.wait(Math.min(timeLeft, 250l));
} catch (InterruptedException ie) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("InterruptedException while Outbound window is full (" + _outboundPackets.size() + "/" + _activeResends + ")");
throw ie;
}
} else {
// + "), waiting indefinitely");
try {
_outboundPackets.wait(250);
} catch (InterruptedException ie) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("InterruptedException while Outbound window is full (" + _outboundPackets.size() + "/" + _activeResends + ")");
throw ie;
}
// 10*1000
}
} else {
_context.statManager().addRateData("stream.chokeSizeEnd", _outboundPackets.size());
return true;
}
}
}
}
use of net.i2p.client.streaming.I2PSocketException in project i2p.i2p by i2p.
the class Connection method resetReceived.
/**
* Notify that a reset was received.
* May be called multiple times.
*/
public void resetReceived() {
if (!_resetReceived.compareAndSet(false, true))
return;
IOException ioe = new I2PSocketException(I2PSocketException.STATUS_CONNECTION_RESET);
_outputStream.streamErrorOccurred(ioe);
_inputStream.streamErrorOccurred(ioe);
_connectionError = "Connection reset";
synchronized (_connectLock) {
_connectLock.notifyAll();
}
// RFC 793 end of section 3.4: We are completely done.
disconnectComplete();
}
Aggregations