net.i2p.i2ptunnel

## Class I2PTunnelRunner

- java.lang.Object
- - java.lang.Thread
  - - net.i2p.util.I2PThread
    - - net.i2p.util.I2PAppThread
      - - net.i2p.i2ptunnel.I2PTunnelRunner

- All Implemented Interfaces:
    Runnable, I2PSocket.SocketErrorListener, LimitOutputStream.DoneCallback
  Direct Known Subclasses:
    I2PTunnelHTTPClientRunner

      public class I2PTunnelRunner
      extends I2PAppThread
      implements I2PSocket.SocketErrorListener, LimitOutputStream.DoneCallback

  Thread that forwards traffic between an I2PSocket and a TCP Socket.

  I2PTunnelRunner implements the core bidirectional data forwarding between I2P and TCP network connections. It spawns two StreamForwarder threads: one for each direction of communication (I2P to TCP and TCP to I2P).

  Connection Flow:

  1. Runner is created with connected I2PSocket and TCP Socket
  2. Initial data may be sent immediately via initialI2PData/initialSocketData
  3. Two StreamForwarder threads are spawned for bidirectional streaming
  4. Runner monitors both connections for errors or disconnection
  5. On completion or failure, callbacks may be invoked and sockets are closed

  Keep-Alive Support: When keep-alive is enabled for either connection, the runner may skip spawning one direction of forwarding if no data is expected. This optimization is used for simple GET requests that don't require responses.

  Thread Safety: This class uses locks (slock) to coordinate socket access and prevent concurrent writes from multiple threads. The finishLock ensures thread-safe state transitions.

  See Also:
    `toI2P`, `fromI2P`, `I2PTunnelServer`

- - ### Nested Class Summary

    Nested Classes
    Modifier and Type | Class and Description
    --- | ---
    `static interface` | `I2PTunnelRunner.FailCallback` For use in new constructor
    `static interface` | `I2PTunnelRunner.SuccessCallback` Callback interface for successful tunnel operation completion.

    - ### Nested classes/interfaces inherited from class net.i2p.util.I2PThread

      `I2PThread.OOMEventListener`

    - ### Nested classes/interfaces inherited from class java.lang.Thread

      `Thread.State, Thread.UncaughtExceptionHandler`

  - ### Field Summary

    Fields
    Modifier and Type | Field and Description
    --- | ---
    `protected boolean` | `_keepAliveI2P`
    `protected boolean` | `_keepAliveSocket`
    `protected Log` | `_log`
    `(package private) static int` | `MAX_PACKET_SIZE` Max bytes streamed in a packet - smaller ones might be filled up to this size.
    `(package private) static int` | `NETWORK_BUFFER_SIZE`

    - ### Fields inherited from class java.lang.Thread

      `MAX_PRIORITY, MIN_PRIORITY, NORM_PRIORITY`

  - ### Constructor Summary

    Constructors
    Constructor and Description
    `I2PTunnelRunner(Socket s, I2PSocket i2ps, Object slock, byte[] initialI2PData, byte[] initialSocketData, List<I2PSocket> sockList, I2PTunnelRunner.FailCallback onFail)` Recommended new constructor.
    `I2PTunnelRunner(Socket s, I2PSocket i2ps, Object slock, byte[] initialI2PData, byte[] initialSocketData, List<I2PSocket> sockList, I2PTunnelRunner.FailCallback onFail, boolean keepAliveI2P, boolean keepAliveSocket)` With keepAlive args.

  - ### Method Summary

    All Methods Instance Methods Concrete Methods
    Modifier and Type | Method and Description
    --- | ---
    `protected void` | `close(OutputStream out, InputStream in, OutputStream i2pout, InputStream i2pin, Socket s, I2PSocket i2ps, Thread t1, Thread t2)` Warning - overridden in I2PTunnelHTTPClientRunner.
    `(package private) boolean` | `getKeepAliveI2P()` Checks if the I2P socket should be kept open after data transfer.
    `(package private) boolean` | `getKeepAliveSocket()` Checks if the local socket should be kept open after data transfer.
    `protected InputStream` | `getSocketIn()` Gets the TCP socket input stream.
    `protected OutputStream` | `getSocketOut()` Gets the TCP socket output stream.
    `long` | `getStartedOn()` Returns the timestamp when this runner started.
    `void` | `run()`
    `void` | `setSuccessCallback(I2PTunnelRunner.SuccessCallback sc)` Sets a callback to be invoked on successful data transfer.
    `void` | `streamDone()` The DoneCallback for the I2P socket.

    - ### Methods inherited from class net.i2p.util.I2PAppThread

      `addOOMEventThreadListener, fireOOM, removeOOMEventThreadListener`

    - ### Methods inherited from class net.i2p.util.I2PThread

      `addOOMEventListener, removeOOMEventListener, start`

    - ### Methods inherited from class java.lang.Thread

      `activeCount, checkAccess, clone, countStackFrames, currentThread, destroy, dumpStack, enumerate, getAllStackTraces, getContextClassLoader, getDefaultUncaughtExceptionHandler, getId, getName, getPriority, getStackTrace, getState, getThreadGroup, getUncaughtExceptionHandler, holdsLock, interrupt, interrupted, isAlive, isDaemon, isInterrupted, join, join, join, resume, setContextClassLoader, setDaemon, setDefaultUncaughtExceptionHandler, setName, setPriority, setUncaughtExceptionHandler, sleep, sleep, stop, stop, suspend, toString, yield`

    - ### Methods inherited from class java.lang.Object

      `equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait`

    - ### Methods inherited from interface net.i2p.client.streaming.I2PSocket.SocketErrorListener

      `errorOccurred`

- - ### Field Detail

    - #### _keepAliveI2P

          protected volatile boolean _keepAliveI2P

    - #### _keepAliveSocket

          protected volatile boolean _keepAliveSocket

    - #### _log

          protected final Log _log

    - #### MAX_PACKET_SIZE

          static int MAX_PACKET_SIZE

      Max bytes streamed in a packet - smaller ones might be filled up to this size. Larger ones are not split (at least not on Sun's impl of BufferedOutputStream), but that is the streaming api's job...

    - #### NETWORK_BUFFER_SIZE

          static final int NETWORK_BUFFER_SIZE

  - ### Constructor Detail

    - #### I2PTunnelRunner

          public I2PTunnelRunner(Socket s,
                                 I2PSocket i2ps,
                                 Object slock,
                                 byte[] initialI2PData,
                                 byte[] initialSocketData,
                                 List<I2PSocket> sockList,
                                 I2PTunnelRunner.FailCallback onFail)

      Recommended new constructor. Does NOT start itself. Caller must call start().
      Parameters:
        `slock` - the socket lock, non-null
        `initialI2PData` - may be null
        `initialSocketData` - may be null
        `sockList` - may be null. Caller must add i2ps to the list! It will be removed here on completion. Will synchronize on slock when removing.
        `onFail` - May be null. If non-null and no data (except initial data) was received, it will be run before closing s.

    - #### I2PTunnelRunner

          public I2PTunnelRunner(Socket s,
                                 I2PSocket i2ps,
                                 Object slock,
                                 byte[] initialI2PData,
                                 byte[] initialSocketData,
                                 List<I2PSocket> sockList,
                                 I2PTunnelRunner.FailCallback onFail,
                                 boolean keepAliveI2P,
                                 boolean keepAliveSocket)

      With keepAlive args. Does NOT start itself. Caller must call start().
      Parameters:
        `slock` - the socket lock, non-null
        `initialI2PData` - may be null
        `initialSocketData` - may be null
        `sockList` - may be null. Caller must add i2ps to the list! It will be removed here on completion. Will synchronize on slock when removing.
        `onFail` - May be null. If non-null and no data (except initial data) was received, it will be run before closing s.
        `keepAliveI2P` - Do not close the I2P socket when done.
        `keepAliveSocket` - Do not close the local socket when done. For client side only; must be false for server side. NO data will be forwarded from the socket to the i2psocket other than initialI2PData if this is true.

  - ### Method Detail

    - #### close

          protected void close(OutputStream out,
                               InputStream in,
                               OutputStream i2pout,
                               InputStream i2pin,
                               Socket s,
                               I2PSocket i2ps,
                               Thread t1,
                               Thread t2)
                        throws InterruptedException

      Warning - overridden in I2PTunnelHTTPClientRunner. Here we ignore keepalive and always close both sides. The HTTP flavor handles keepalive.
      Parameters:
        `out` - may be null
        `in` - may be null
        `i2pout` - may be null
        `i2pin` - may be null
        `t1` - may be null
        `t2` - may be null, ignored, we only join t1
      Throws:
        `InterruptedException`

    - #### getKeepAliveI2P

          boolean getKeepAliveI2P()

      Checks if the I2P socket should be kept open after data transfer.

      On the client side, this is true only if the browser and server both support HTTP keep-alive. On the server side, it's true only if the client supports keep-alive.

      Returns:
        true if the I2P socket should remain open for reuse

    - #### getKeepAliveSocket

          boolean getKeepAliveSocket()

      Checks if the local socket should be kept open after data transfer.

      Usually true for client-side connections (browser to proxy). Always false for server-side connections (I2P to local service).

      Returns:
        true if the local socket should remain open for reuse

    - #### getSocketIn

          protected InputStream getSocketIn()
                                     throws IOException

      Gets the TCP socket input stream.

      This method is protected to allow subclasses to override socket access for testing or special handling (e.g., SSL unwrapping).

      Returns:
        the TCP socket's input stream
      Throws:
        `IOException` - if the socket is closed

    - #### getSocketOut

          protected OutputStream getSocketOut()
                                       throws IOException

      Gets the TCP socket output stream.
      Returns:
        the TCP socket's output stream
      Throws:
        `IOException` - if the socket is closed

    - #### getStartedOn

          public long getStartedOn()

      Returns the timestamp when this runner started.

      This value is set at construction time and represents when the runner was created, not when it started executing.

      Returns:
        the timestamp in milliseconds since epoch when this runner was created

    - #### run

          public void run()

      Specified by:
        `run` in interface `Runnable`
      Overrides:
        `run` in class `I2PThread`

    - #### setSuccessCallback

          public void setSuccessCallback(I2PTunnelRunner.SuccessCallback sc)

      Sets a callback to be invoked on successful data transfer.

      The callback is invoked after the first byte of data is received from the destination, not when the entire transfer completes. Only one of SuccessCallback, onTimeout, or onFail will be called.

      Parameters:
        `sc` - the callback to invoke on success, may be null

    - #### streamDone

          public void streamDone()

      The DoneCallback for the I2P socket.
      Specified by:
        `streamDone` in interface `LimitOutputStream.DoneCallback`