All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.schmizz.sshj.connection.channel.Window Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C)2009 - SSHJ Contributors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.schmizz.sshj.connection.channel;

import net.schmizz.sshj.common.LoggerFactory;
import net.schmizz.sshj.common.SSHRuntimeException;
import net.schmizz.sshj.connection.ConnectionException;
import org.slf4j.Logger;

import java.util.concurrent.TimeUnit;

public abstract class Window {

    protected final Logger log;

    protected final Object lock = new Object();

    protected final int maxPacketSize;

    protected long size;

    public Window(long initialWinSize, int maxPacketSize, LoggerFactory loggerFactory) {
        size = initialWinSize;
        this.maxPacketSize = maxPacketSize;
        log = loggerFactory.getLogger(getClass());
    }

    public void expand(long inc) {
        synchronized (lock) {
            size += inc;
            log.debug("Increasing by {} up to {}", inc, size);
            lock.notifyAll();
        }
    }

    public int getMaxPacketSize() {
        return maxPacketSize;
    }

    public long getSize() {
        synchronized (lock) {
            return size;
        }
    }

    public void consume(long dec)
            throws ConnectionException {
        synchronized (lock) {
            size -= dec;
            log.debug("Consuming by {} down to {}", dec, size);
            if (size < 0) {
                throw new ConnectionException("Window consumed to below 0");
            }
        }
    }

    @Override
    public String toString() {
        return "[winSize=" + size + "]";
    }

    /** Controls how much data we can send before an adjustment notification from remote end is required. */
    public static final class Remote
            extends Window {
        private final long timeoutMs;

        public Remote(long initialWinSize, int maxPacketSize, long timeoutMs, LoggerFactory loggerFactory) {
            super(initialWinSize, maxPacketSize, loggerFactory);
            this.timeoutMs = timeoutMs;
        }

        public long awaitExpansion(long was) throws ConnectionException {
            synchronized (lock) {
                long end = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(timeoutMs);
                while (size <= was) {
                    log.debug("Waiting, need size to grow from {} bytes", was);
                    try {
                        lock.wait(timeoutMs);
                        if ((size <= was) && ((System.nanoTime() - end) > 0)) {
                            throw new ConnectionException("Timeout when trying to expand the window size");
                        }
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        throw new ConnectionException(ie);
                    }
                }
                return size;
            }
        }

        public void consume(long howMuch) {
            try {
                super.consume(howMuch);
            } catch (ConnectionException e) { // It's a bug if we consume more than remote allowed
                throw new SSHRuntimeException(e);
            }
        }

    }

    /** Controls how much data remote end can send before an adjustment notification from us is required. */
    public static final class Local
            extends Window {

        private final long initialSize;
        private final long threshold;

        public Local(long initialWinSize, int maxPacketSize, LoggerFactory loggerFactory) {
            super(initialWinSize, maxPacketSize, loggerFactory);
            this.initialSize = initialWinSize;
            threshold = Math.min(maxPacketSize * 20, initialSize / 4);
        }

        public long neededAdjustment() {
            synchronized (lock) {
                return (size <= threshold) ? (initialSize - size) : 0;
            }
        }

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy