Package com.facebook.presto.jdbc.internal.airlift.http.client.netty.socks

Source Code of com.facebook.presto.jdbc.internal.airlift.http.client.netty.socks.Socks4ClientBootstrap

/*
* Copyright (C) 2012-2013 Facebook, Inc.
*
* 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 com.facebook.presto.jdbc.internal.airlift.http.client.netty.socks;

import com.facebook.presto.jdbc.internal.guava.net.HostAndPort;
import com.facebook.presto.jdbc.internal.netty.bootstrap.ClientBootstrap;
import com.facebook.presto.jdbc.internal.netty.buffer.ChannelBuffer;
import com.facebook.presto.jdbc.internal.netty.channel.Channel;
import com.facebook.presto.jdbc.internal.netty.channel.ChannelFactory;
import com.facebook.presto.jdbc.internal.netty.channel.ChannelFuture;
import com.facebook.presto.jdbc.internal.netty.channel.ChannelFutureListener;
import com.facebook.presto.jdbc.internal.netty.channel.ChannelPipeline;
import com.facebook.presto.jdbc.internal.netty.channel.ChannelPipelineFactory;
import com.facebook.presto.jdbc.internal.netty.channel.Channels;
import com.facebook.presto.jdbc.internal.netty.handler.codec.frame.FixedLengthFrameDecoder;

import java.net.InetSocketAddress;
import java.net.SocketAddress;

import static com.facebook.presto.jdbc.internal.airlift.http.client.netty.socks.SocksProtocols.createSock4aPacket;
import static com.facebook.presto.jdbc.internal.airlift.http.client.netty.socks.SocksProtocols.createSocks4packet;

/**
* ClientBootstrap for connecting via SOCKS proxy.
* Currently only SOCK4 is supported since we don't do authentication anyway.
* <p/>
* See http://en.wikipedia.org/wiki/SOCKS
*/
public class Socks4ClientBootstrap
        extends ClientBootstrap
{
    static final String FRAME_DECODER = "frameDecoder";
    static final String HANDSHAKE = "handshake";

    private final HostAndPort socksProxyAddr;

    public Socks4ClientBootstrap(ChannelFactory channelFactory, HostAndPort socksProxyAddr)
    {
        super(channelFactory);
        this.socksProxyAddr = socksProxyAddr;
    }

    /**
     * Hijack super class's pipelineFactory and return our own that
     * does the connect to SOCKS proxy and does the handshake.
     */
    @Override
    public ChannelPipelineFactory getPipelineFactory()
    {
        return new ChannelPipelineFactory()
        {
            @Override
            public ChannelPipeline getPipeline()
                    throws Exception
            {
                final ChannelPipeline cp = Channels.pipeline();
                cp.addLast(FRAME_DECODER, new FixedLengthFrameDecoder(8));
                cp.addLast(HANDSHAKE, new Socks4HandshakeHandler(Socks4ClientBootstrap.super.getPipelineFactory()));
                return cp;
            }
        };
    }

    /**
     * Hijack the connect method to connect to socks proxy and then
     * send the connection handshake once connection to proxy is established.
     *
     * @return returns a ChannelFuture, it will be ready once the connection to
     *         socks and the remote address is established ( i.e. after the handshake completes )
     */
    @Override
    public ChannelFuture connect(final SocketAddress remoteAddress)
    {
        if (!(remoteAddress instanceof InetSocketAddress)) {
            throw new IllegalArgumentException("expecting InetSocketAddress");
        }
        final SettableChannelFuture settableChannelFuture = new SettableChannelFuture();
        super.connect(new InetSocketAddress(socksProxyAddr.getHostText(), socksProxyAddr.getPort())).addListener(new ChannelFutureListener()
        {
            @Override
            public void operationComplete(ChannelFuture future)
                    throws Exception
            {
                settableChannelFuture.setChannel(future.getChannel());
                if (future.isSuccess()) {
                    socksConnect(future.getChannel(), (InetSocketAddress) remoteAddress).addListener(new ChannelFutureListener()
                    {
                        @Override
                        public void operationComplete(ChannelFuture innerFuture)
                                throws Exception
                        {
                            if (innerFuture.isSuccess()) {
                                settableChannelFuture.setSuccess();
                            }
                            else {
                                settableChannelFuture.setFailure(innerFuture.getCause());
                            }
                        }
                    });
                }
                else {
                    settableChannelFuture.setFailure(future.getCause());
                }
            }
        });
        return settableChannelFuture;
    }


    /**
     * try to look at the remoteAddress and decide to use SOCKS4 or SOCKS4a handshake
     * packet.
     */
    private ChannelFuture socksConnect(Channel channel, InetSocketAddress remoteAddress)
    {
        ChannelBuffer handshake = null;
        if ((remoteAddress.getAddress() == null && remoteAddress.getHostName() != null) || remoteAddress.getHostName().equals("localhost")) {
            handshake = createSock4aPacket(remoteAddress.getHostName(), remoteAddress.getPort());
        }
        if (remoteAddress.getAddress() != null) {
            handshake = createSocks4packet(remoteAddress.getAddress(), remoteAddress.getPort());
        }

        if (handshake == null) {
            throw new IllegalArgumentException("Invalid Address " + remoteAddress);
        }

        channel.write(handshake);
        return ((Socks4HandshakeHandler) channel.getPipeline().get("handshake")).getChannelFuture();
    }
}
TOP

Related Classes of com.facebook.presto.jdbc.internal.airlift.http.client.netty.socks.Socks4ClientBootstrap

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.