me.xingrz.prox.tcp.tunnel.RemoteTunnel.java Source code

Java tutorial

Introduction

Here is the source code for me.xingrz.prox.tcp.tunnel.RemoteTunnel.java

Source

/*
 * Copyright (C) 2015 XiNGRZ <chenxingyu92@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

package me.xingrz.prox.tcp.tunnel;

import org.apache.commons.io.IOUtils;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;

import me.xingrz.prox.selectable.Connectible;
import me.xingrz.prox.tcp.Blacklist;

public abstract class RemoteTunnel extends Tunnel implements Connectible {

    private InetSocketAddress address;

    private static SocketChannel makeChannel() throws IOException {
        SocketChannel channel = SocketChannel.open();
        channel.configureBlocking(false);
        channel.socket().bind(new InetSocketAddress(0));
        return channel;
    }

    public RemoteTunnel(Selector selector, String sessionKey) throws IOException {
        super(selector, makeChannel(), sessionKey);
    }

    public void connect(InetSocketAddress address) throws IOException {
        this.address = address;

        if (channel.connect(address)) {
            onConnectedInternal();
        } else {
            channel.register(selector, SelectionKey.OP_CONNECT, this);
        }
    }

    @Override
    public final void onConnectible(SelectionKey key) {
        try {
            if (channel.finishConnect()) {
                onConnectedInternal();
            } else {
                IOUtils.closeQuietly(this);
            }
        } catch (SocketTimeoutException e) {
            Blacklist.countUp(address.getAddress());
            logger.w(e, "Timeout finishing connect");
            IOUtils.closeQuietly(this);
        } catch (IOException e) {
            logger.w(e, "Error finishing connect");
            IOUtils.closeQuietly(this);
        }
    }

    private void onConnectedInternal() throws IOException {
        onConnected();
        beginReceiving();
        handshake();
    }

    protected abstract void onConnected();

    protected void handshake() {
        establish();
    }

    protected void establish() {
        onEstablished();
        writeRemaining();
    }

    protected abstract void onEstablished();

    /**
     * Tunnel ??????
     *
     * @return ??
     */
    public boolean isEstablished() {
        return channel.isConnected();
    }

    /**
     * {@inheritDoc}
     * {@link me.xingrz.prox.tcp.tunnel.RemoteTunnel}  {@link #write(java.nio.ByteBuffer)}
     * ? {@link #connect(java.net.InetSocketAddress)} ??
     */
    @Override
    public boolean write(ByteBuffer buffer) {
        if (!isEstablished()) {
            logger.v("Buffered %d bytes of write since tunnel is not established", buffer.remaining());
            keepRemaining(buffer);
            return false;
        }

        return super.write(buffer);
    }

}