Search in sources :

Example 1 with I2PSocketException

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;
    }
}
Also used : IOException(java.io.IOException) I2PSocketException(net.i2p.client.streaming.I2PSocketException)

Example 2 with I2PSocketException

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) {
            }
        }
    }
}
Also used : I2PSocketException(net.i2p.client.streaming.I2PSocketException) SocketException(java.net.SocketException) BufferedInputStream(java.io.BufferedInputStream) InputStream(java.io.InputStream) OutputStream(java.io.OutputStream) IOException(java.io.IOException) InterruptedIOException(java.io.InterruptedIOException) I2PSocketException(net.i2p.client.streaming.I2PSocketException) SSLException(javax.net.ssl.SSLException) IOException(java.io.IOException) InterruptedIOException(java.io.InterruptedIOException) I2PSocketException(net.i2p.client.streaming.I2PSocketException) SocketException(java.net.SocketException) SSLException(javax.net.ssl.SSLException) InternalSocket(net.i2p.util.InternalSocket) BufferedInputStream(java.io.BufferedInputStream)

Example 3 with I2PSocketException

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 &lt;= 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;
            }
        }
    }
}
Also used : IOException(java.io.IOException) I2PSocketException(net.i2p.client.streaming.I2PSocketException)

Example 4 with I2PSocketException

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();
}
Also used : IOException(java.io.IOException) I2PSocketException(net.i2p.client.streaming.I2PSocketException)

Aggregations

IOException (java.io.IOException)4 I2PSocketException (net.i2p.client.streaming.I2PSocketException)4 BufferedInputStream (java.io.BufferedInputStream)1 InputStream (java.io.InputStream)1 InterruptedIOException (java.io.InterruptedIOException)1 OutputStream (java.io.OutputStream)1 SocketException (java.net.SocketException)1 SSLException (javax.net.ssl.SSLException)1 InternalSocket (net.i2p.util.InternalSocket)1