<commit_before>package net.i2p.client.streaming;

import java.util.Properties;

/**
 * Define the current options for the con (and allow custom tweaking midstream)
 *
 */
public class ConnectionOptions extends I2PSocketOptionsImpl {
    private int _connectDelay;
    private boolean _fullySigned;
    private volatile int _windowSize;
    private int _receiveWindow;
    private int _profile;
    private int _rtt;
    private int _rttDev;
    private int _rto;
    private int _trend[];
    private int _resendDelay;
    private int _sendAckDelay;
    private int _maxMessageSize;
    private int _choke;
    private int _maxResends;
    private int _inactivityTimeout;
    private int _inactivityAction;
    private int _inboundBufferSize;
    private int _maxWindowSize;
    private int _congestionAvoidanceGrowthRateFactor;
    private int _slowStartGrowthRateFactor;

    public static final int PROFILE_BULK = 1;
    public static final int PROFILE_INTERACTIVE = 2;
    
    /** on inactivity timeout, do nothing */
    public static final int INACTIVITY_ACTION_NOOP = 0;
    /** on inactivity timeout, close the connection */
    public static final int INACTIVITY_ACTION_DISCONNECT = 1;
    /** on inactivity timeout, send a payload message */
    public static final int INACTIVITY_ACTION_SEND = 2;
    
    public static final String PROP_CONNECT_DELAY = "i2p.streaming.connectDelay";
    public static final String PROP_PROFILE = "i2p.streaming.profile";
    public static final String PROP_MAX_MESSAGE_SIZE = "i2p.streaming.maxMessageSize";
    public static final String PROP_MAX_RESENDS = "i2p.streaming.maxResends";
    public static final String PROP_INITIAL_RTT = "i2p.streaming.initialRTT";
    public static final String PROP_INITIAL_RESEND_DELAY = "i2p.streaming.initialResendDelay";
    public static final String PROP_INITIAL_ACK_DELAY = "i2p.streaming.initialAckDelay";
    public static final String PROP_INITIAL_WINDOW_SIZE = "i2p.streaming.initialWindowSize";
    public static final String PROP_INITIAL_RECEIVE_WINDOW = "i2p.streaming.initialReceiveWindow";
    public static final String PROP_INACTIVITY_TIMEOUT = "i2p.streaming.inactivityTimeout";
    public static final String PROP_INACTIVITY_ACTION = "i2p.streaming.inactivityAction";
    public static final String PROP_MAX_WINDOW_SIZE = "i2p.streaming.maxWindowSize";
    public static final String PROP_CONGESTION_AVOIDANCE_GROWTH_RATE_FACTOR = "i2p.streaming.congestionAvoidanceGrowthRateFactor";
    public static final String PROP_SLOW_START_GROWTH_RATE_FACTOR = "i2p.streaming.slowStartGrowthRateFactor";
    
    private static final int TREND_COUNT = 3;
    static final int INITIAL_WINDOW_SIZE = 12;
    static final int DEFAULT_MAX_SENDS = 8;
    
    static final int MIN_WINDOW_SIZE = 1;
    
    public ConnectionOptions() {
        super();
    }
    
    public ConnectionOptions(Properties opts) {
        super(opts);
    }
    
    public ConnectionOptions(I2PSocketOptions opts) {
        super(opts);
    }
    
    public ConnectionOptions(ConnectionOptions opts) {
        super(opts);
        if (opts != null) {
            setMaxWindowSize(opts.getMaxWindowSize());
            setConnectDelay(opts.getConnectDelay());
            setProfile(opts.getProfile());
            setRTT(opts.getRTT());
            setRequireFullySigned(opts.getRequireFullySigned());
            setWindowSize(opts.getWindowSize());
            setResendDelay(opts.getResendDelay());
            setMaxMessageSize(opts.getMaxMessageSize());
            setChoke(opts.getChoke());
            setMaxResends(opts.getMaxResends());
            setInactivityTimeout(opts.getInactivityTimeout());
            setInactivityAction(opts.getInactivityAction());
            setInboundBufferSize(opts.getInboundBufferSize());
            setCongestionAvoidanceGrowthRateFactor(opts.getCongestionAvoidanceGrowthRateFactor());
            setSlowStartGrowthRateFactor(opts.getSlowStartGrowthRateFactor());
            setWriteTimeout(opts.getWriteTimeout());
            setReadTimeout(opts.getReadTimeout());
        }
    }
    
	@Override
    protected void init(Properties opts) {
        super.init(opts);
        _trend = new int[TREND_COUNT];
        
        setMaxWindowSize(getInt(opts, PROP_MAX_WINDOW_SIZE, Connection.MAX_WINDOW_SIZE));
        setConnectDelay(getInt(opts, PROP_CONNECT_DELAY, -1));
        setProfile(getInt(opts, PROP_PROFILE, PROFILE_BULK));
        setMaxMessageSize(getInt(opts, PROP_MAX_MESSAGE_SIZE, 960)); // 960 fits inside a single tunnel message
        setRTT(getInt(opts, PROP_INITIAL_RTT, 10*1000));<commit_msg>    * Streaming: Increase MTU to 1730 (was 960);       see ConnectionOptions.java for analysis<commit_after>package net.i2p.client.streaming;

import java.util.Properties;

/**
 * Define the current options for the con (and allow custom tweaking midstream)
 *
 */
public class ConnectionOptions extends I2PSocketOptionsImpl {
    private int _connectDelay;
    private boolean _fullySigned;
    private volatile int _windowSize;
    private int _receiveWindow;
    private int _profile;
    private int _rtt;
    private int _rttDev;
    private int _rto;
    private int _trend[];
    private int _resendDelay;
    private int _sendAckDelay;
    private int _maxMessageSize;
    private int _choke;
    private int _maxResends;
    private int _inactivityTimeout;
    private int _inactivityAction;
    private int _inboundBufferSize;
    private int _maxWindowSize;
    private int _congestionAvoidanceGrowthRateFactor;
    private int _slowStartGrowthRateFactor;

    public static final int PROFILE_BULK = 1;
    public static final int PROFILE_INTERACTIVE = 2;
    
    /** on inactivity timeout, do nothing */
    public static final int INACTIVITY_ACTION_NOOP = 0;
    /** on inactivity timeout, close the connection */
    public static final int INACTIVITY_ACTION_DISCONNECT = 1;
    /** on inactivity timeout, send a payload message */
    public static final int INACTIVITY_ACTION_SEND = 2;
    
    public static final String PROP_CONNECT_DELAY = "i2p.streaming.connectDelay";
    public static final String PROP_PROFILE = "i2p.streaming.profile";
    public static final String PROP_MAX_MESSAGE_SIZE = "i2p.streaming.maxMessageSize";
    public static final String PROP_MAX_RESENDS = "i2p.streaming.maxResends";
    public static final String PROP_INITIAL_RTT = "i2p.streaming.initialRTT";
    public static final String PROP_INITIAL_RESEND_DELAY = "i2p.streaming.initialResendDelay";
    public static final String PROP_INITIAL_ACK_DELAY = "i2p.streaming.initialAckDelay";
    public static final String PROP_INITIAL_WINDOW_SIZE = "i2p.streaming.initialWindowSize";
    public static final String PROP_INITIAL_RECEIVE_WINDOW = "i2p.streaming.initialReceiveWindow";
    public static final String PROP_INACTIVITY_TIMEOUT = "i2p.streaming.inactivityTimeout";
    public static final String PROP_INACTIVITY_ACTION = "i2p.streaming.inactivityAction";
    public static final String PROP_MAX_WINDOW_SIZE = "i2p.streaming.maxWindowSize";
    public static final String PROP_CONGESTION_AVOIDANCE_GROWTH_RATE_FACTOR = "i2p.streaming.congestionAvoidanceGrowthRateFactor";
    public static final String PROP_SLOW_START_GROWTH_RATE_FACTOR = "i2p.streaming.slowStartGrowthRateFactor";
    
    private static final int TREND_COUNT = 3;
    static final int INITIAL_WINDOW_SIZE = 12;
    static final int DEFAULT_MAX_SENDS = 8;
    
    static final int MIN_WINDOW_SIZE = 1;
    
    /**
     *  OK, here is the calculation on the message size to fit in a single
     *  tunnel message without fragmentation.
     *  This is based on documentation, the code, and logging, however there are still
     *  some parts that could use more research.
     *
     *  1024 Tunnel Message
     *  - 21 Header (see router/tunnel/BatchedPreprocessor.java)
     * -----
     *  1003 Tunnel Payload
     *  - 39 Unfragmented instructions (see router/tunnel/TrivialPreprocessor.java)
     * -----
     *   964 Unfragmented I2NP Message
     *  - 20 ??
     * -----
     *   944 Garlic Message padded to 16 bytes
     *  -  0 Pad to 16 bytes (why?)
     * -----
     *   944 Garlic Message (assumes no bundled leaseSet or keys)
     *  - 71 Garlic overhead
     * -----
     *   873 Tunnel Data Message
     *  - 84 ??
     * -----
     *   789 Gzipped I2NP message
     *  - 23 Gzip 10 byte header, 5 byte block header, 8 byte trailer (yes we always use gzip, but it
     *       probably isn't really compressing, just adding the headers and trailer, since
     *       HTTP Server already compresses, and most P2P files aren't compressible.
     *       (see client/I2PSessionImpl2.java, util/ReusableGZipOutputStream.java, and the gzip and deflate specs)
     * -----
     *   766
     *  - 28 Streaming header (24 min, but leave room for a nack or other optional things) (See Packet.java)
     * -----
     *   738 Streaming message size
     *
     *
     * FOR TWO TUNNEL MESSAGES:
     *
     *  2048 2 Tunnel Messages
     *  - 42 2 Headers
     * -----
     *  2006 Tunnel Payload
     *  - 50 Fragmented instructions (43 for first + 7 for second)
     * -----
     *  1956 Unfragmented I2NP Message
     *  - 20 ??
     * -----
     *  1936 Garlic Message padded to 16 bytes
     *  1936
     *  -  0 Pad to 16 bytes
     * -----
     *  1936 Garlic Message
     *  - 71 Garlic overhead
     * -----
     *  1865 Tunnel Data Message
     *  - 84 ??
     * -----
     *  1781 Gzipped I2NP message
     *  - 23 Gzip header
     * -----
     *  1758
     *  - 28 Streaming header
     * -----
     *  1730 Streaming message size to fit in 2 tunnel messages
     *
     *
     * Similarly:
     *   3 msgs: 2722
     *   4 msgs: 3714
     *
     *
     * Before release 0.6.1.14 this was 4096.
     * From release 0.6.1.14 through release 0.6.4, this was 960.
     * It was claimed in the comment that this fit in
     * a single tunnel message (and the checkin comment says the goal was to
     * increase reliability at the expense of throughput),
     * clearly from the math above that was not correct.
     * (Before 0.6.2, the reply leaseSet was bundled with every message, so it didn't even
     * fit in TWO tunnel messages - more like 2 1/3)
     *
     * Now, it's not clear how often we will get the ideal situation (no reply leaseSet bundling,
     * no key bundling, and especially not having a small message ahead of you, which will then cause
     * fragmentation for all subsequent messages until the queue is emptied - BatchedPreprocessor
     * doesn't do reordering, and it isn't clear to me if it could). In particular the initial
     * messages in a new stream are much larger due to the leaseSet and key bundling.
     * But for long-lived streams (like with i2psnark) this should pay dividends.
     * The tunnel.batch* stats should provide some data for test comparisons.
     *
     * As MTU and MRU are identical and are negotiated to the lowest value
     * for the two ends, you can't do widespread testing of a higher value.
     * Unless we change to allow MTU and MRU to be different,
     * which would be a pain because it would mess up our buffer scheme.
     * Both 738 and 1730 have been tested to verify that the math above is correct.
     * So let's try 1730 for release 0.6.5. This will allow for 738 testing as well,
     * with i2p.streaming.maxMessageSize=738 (in configadvanced.jsp, or in i2ptunnel, or
     * i2psnark, for example).
     *
     * Not that an isolated single packet is very common, but
     * in this case, 960 was 113.3% total overhead.
     * Compared to 738 (38.8% overhead) and 1730 (18.4%).
     *
     */
    public static final int DEFAULT_MAX_MESSAGE_SIZE = 1730;

    public ConnectionOptions() {
        super();
    }
    
    public ConnectionOptions(Properties opts) {
        super(opts);
    }
    
    public ConnectionOptions(I2PSocketOptions opts) {
        super(opts);
    }
    
    public ConnectionOptions(ConnectionOptions opts) {
        super(opts);
        if (opts != null) {
            setMaxWindowSize(opts.getMaxWindowSize());
            setConnectDelay(opts.getConnectDelay());
            setProfile(opts.getProfile());
            setRTT(opts.getRTT());
            setRequireFullySigned(opts.getRequireFullySigned());
            setWindowSize(opts.getWindowSize());
            setResendDelay(opts.getResendDelay());
            setMaxMessageSize(opts.getMaxMessageSize());
            setChoke(opts.getChoke());
            setMaxResends(opts.getMaxResends());
            setInactivityTimeout(opts.getInactivityTimeout());
            setInactivityAction(opts.getInactivityAction());
            setInboundBufferSize(opts.getInboundBufferSize());
            setCongestionAvoidanceGrowthRateFactor(opts.getCongestionAvoidanceGrowthRateFactor());
            setSlowStartGrowthRateFactor(opts.getSlowStartGrowthRateFactor());
            setWriteTimeout(opts.getWriteTimeout());
            setReadTimeout(opts.getReadTimeout());
        }
    }
    
	@Override
    protected void init(Properties opts) {
        super.init(opts);
        _trend = new int[TREND_COUNT];
        
        setMaxWindowSize(getInt(opts, PROP_MAX_WINDOW_SIZE, Connection.MAX_WINDOW_SIZE));
        setConnectDelay(getInt(opts, PROP_CONNECT_DELAY, -1));
        setProfile(getInt(opts, PROP_PROFILE, PROFILE_BULK));
        setMaxMessageSize(getInt(opts, PROP_MAX_MESSAGE_SIZE, DEFAULT_MAX_MESSAGE_SIZE));
        setRTT(getInt(opts, PROP_INITIAL_RTT, 10*1000));
{'fraction_non_alphanumeric': 0.0771158950162194, 'fraction_numerical': 0.021453848422294308, 'mean_word_length': 2.9582725415815583, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1090100', 'n_tokens_mistral': 4219, 'n_tokens_neox': 3963, 'n_words': 1144}