Package de.fhkn.in.uce.connectivitymanager.investigator

Source Code of de.fhkn.in.uce.connectivitymanager.investigator.DeterminingTcpNatMapping

/*
* Copyright (c) 2012 Alexander Diener,
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
package de.fhkn.in.uce.connectivitymanager.investigator;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;

import net.jcip.annotations.Immutable;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.fhkn.in.uce.plugininterface.NATFeatureRealization;
import de.fhkn.in.uce.stun.attribute.OtherAddress;
import de.fhkn.in.uce.stun.attribute.XorMappedAddress;
import de.fhkn.in.uce.stun.header.STUNMessageClass;
import de.fhkn.in.uce.stun.header.STUNMessageMethod;
import de.fhkn.in.uce.stun.message.Message;
import de.fhkn.in.uce.stun.message.MessageReader;
import de.fhkn.in.uce.stun.message.MessageStaticFactory;
import de.fhkn.in.uce.stun.message.MessageWriter;
import de.fhkn.in.uce.stun.util.MessageFormatException;

/**
* Implementation of {@link DeterminingNATFeatureRealization} to investigate the
* mapping behavior in case of TCP connections. This is a implementation of
* section 4.3 of RFC 5780. The tests are extended by examining if the
* realization is connection dependent.
*
* @author Alexander Diener (aldiener@htwg-konstanz.de)
*
*/
@Immutable
final class DeterminingTcpNatMapping implements DeterminingNATFeatureRealization {
    private final Logger logger = LoggerFactory.getLogger(DeterminingTcpNatMapping.class);
    private final int sourcePort;
    private final InetSocketAddress primaryStunServerAddress;

    /**
     * Creates a {@link DeterminingTcpNatMapping} with the given source port.
     * The source port should be the same as used in the application.
     *
     * @param sourcePort
     *            the port which is used by the application
     */
    public DeterminingTcpNatMapping(final int sourcePort, final InetSocketAddress primaryStunServerAddress) {
        this.sourcePort = sourcePort;
        this.primaryStunServerAddress = primaryStunServerAddress;
    }

    @Override
    public NATFeatureRealization executeTest() {
        NATFeatureRealization result = NATFeatureRealization.DONT_CARE;
        try {
            final Message responseI = this.executeTestI(this.primaryStunServerAddress.getAddress(),
                    this.primaryStunServerAddress.getPort());
            final XorMappedAddress mappedAddressI = responseI.getAttribute(XorMappedAddress.class);
            final String localAddress = InetAddress.getLocalHost().getHostAddress();
            if (localAddress.equals(mappedAddressI.getEndpoint().getHostName())
                    && this.sourcePort == mappedAddressI.getEndpoint().getPort()) {
                result = NATFeatureRealization.NOT_REALIZED;
            } else {
                final InetSocketAddress alternateAddress = this.getAlternateSTUNServerAddressFromMessage(responseI);
                final Message responseII = this.executeTestII(alternateAddress.getAddress(),
                        this.primaryStunServerAddress.getPort());
                final XorMappedAddress mappedAddressII = responseII.getAttribute(XorMappedAddress.class);
                if (mappedAddressII.equals(mappedAddressI)) {
                    result = NATFeatureRealization.ENDPOINT_INDEPENDENT;
                } else {
                    final Message responseIII = this.executeTestIII(alternateAddress.getAddress(),
                            alternateAddress.getPort());
                    final XorMappedAddress mappedAddressIII = responseIII.getAttribute(XorMappedAddress.class);
                    if (mappedAddressIII.equals(mappedAddressII)) {
                        result = NATFeatureRealization.ADDRESS_DEPENDENT;
                    } else {
                        final Message responseIV = this.executeTestRun(this.primaryStunServerAddress.getAddress(),
                                this.primaryStunServerAddress.getPort());
                        final XorMappedAddress mappedAddressIV = responseIV.getAttribute(XorMappedAddress.class);
                        if (!mappedAddressIV.equals(mappedAddressI)) {
                            result = NATFeatureRealization.CONNECTION_DEPENDENT;
                        } else {
                            result = NATFeatureRealization.ADDRESS_AND_PORT_DEPENDENT;
                        }
                    }
                }
            }
        } catch (final Exception e) {
            this.logger.error("Exception while investigating NAT mapping behavior.", e);
        }

        return result;
    }

    private Message executeTestI(final InetAddress primaryAddress, final int primaryPort) throws Exception {
        return this.executeTestRun(primaryAddress, primaryPort);
    }

    private Message executeTestII(final InetAddress alternateAddress, final int primaryPort) throws Exception {
        return this.executeTestRun(alternateAddress, primaryPort);
    }

    private Message executeTestIII(final InetAddress alternateAddress, final int alternatePort) throws Exception {
        return this.executeTestRun(alternateAddress, alternatePort);
    }

    private Message executeTestRun(final InetAddress stunServerAddress, final int stunServerPort) throws Exception {
        try {
            final Socket socket = new Socket();
            socket.setReuseAddress(true);
            socket.bind(new InetSocketAddress(this.sourcePort));
            socket.connect(new InetSocketAddress(stunServerAddress, stunServerPort));
            this.sendBindingRequestToStunServer(socket.getOutputStream());
            final Message response = this.receiveBindingResponseFromStunServer(socket.getInputStream());
            socket.close();
            return response;
        } catch (final Exception e) {
            this.logger.error("Exception eccured while executing test", e);
            throw e;
        }
    }

    private void sendBindingRequestToStunServer(final OutputStream out) throws Exception {
        final MessageWriter writer = new MessageWriter(out);
        final Message request = MessageStaticFactory.newSTUNMessageInstance(STUNMessageClass.REQUEST,
                STUNMessageMethod.BINDING);
        writer.writeMessage(request);
    }

    private Message receiveBindingResponseFromStunServer(final InputStream in) throws Exception {
        final MessageReader reader = MessageReader.createMessageReader();
        return reader.readSTUNMessage(in);
    }

    private InetSocketAddress getAlternateSTUNServerAddressFromMessage(final Message message) throws Exception {
        if (!message.hasAttribute(OtherAddress.class)) {
            throw new MessageFormatException("The required OTHER-ADDRESS attribute is not provided.");
        }
        final OtherAddress otherAddress = message.getAttribute(OtherAddress.class);
        return otherAddress.getEndpoint();
    }

    public static void main(String[] args) {
        final InetSocketAddress stunServerAddress = new InetSocketAddress("134.34.165.164", 3478);
        final DeterminingNATFeatureRealization mapping = new DeterminingTcpNatMapping(55553, stunServerAddress);
        final NATFeatureRealization mappingRealization = mapping.executeTest();
        System.out.println(mappingRealization.toString());
    }
}
TOP

Related Classes of de.fhkn.in.uce.connectivitymanager.investigator.DeterminingTcpNatMapping

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.