Package de.fhkn.in.uce.connectivitymanager.manager.source

Source Code of de.fhkn.in.uce.connectivitymanager.manager.source.UnsecureSourceSideConnectionEstablishment

/*
* 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.manager.source;

import java.net.Socket;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

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

import de.fhkn.in.uce.connectivitymanager.connection.configuration.ConnectionConfiguration;
import de.fhkn.in.uce.connectivitymanager.investigator.InfrastructreInvestigator;
import de.fhkn.in.uce.connectivitymanager.investigator.InfrastructureInvestigatorImpl;
import de.fhkn.in.uce.connectivitymanager.manager.ConnectionEstablishment;
import de.fhkn.in.uce.connectivitymanager.manager.ManagerUtil;
import de.fhkn.in.uce.connectivitymanager.manager.ManagerUtilImpl;
import de.fhkn.in.uce.connectivitymanager.mediatorconnection.MediatorConnection;
import de.fhkn.in.uce.connectivitymanager.registry.NATTraversalRegistry;
import de.fhkn.in.uce.connectivitymanager.registry.NATTraversalRegistryImpl;
import de.fhkn.in.uce.connectivitymanager.selector.NATTraversalSelection;
import de.fhkn.in.uce.connectivitymanager.selector.strategy.ConnectionSetupTimeSelection;
import de.fhkn.in.uce.plugininterface.NATBehavior;
import de.fhkn.in.uce.plugininterface.NATSituation;
import de.fhkn.in.uce.plugininterface.NATTraversalTechnique;
import de.fhkn.in.uce.plugininterface.message.NATAttributeTypeDecoder;
import de.fhkn.in.uce.plugininterface.message.NATTraversalTechniqueAttribute;
import de.fhkn.in.uce.stun.attribute.Username;
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;

public final class UnsecureSourceSideConnectionEstablishment implements ConnectionEstablishment {
    private final Logger logger = LoggerFactory.getLogger(UnsecureSourceSideConnectionEstablishment.class);
    // private final MediatorUtil mediatorUtil;
    private final NATTraversalSelection selection;
    private final NATTraversalRegistry registry;
    private final InfrastructreInvestigator investigator;
    private final ManagerUtil managerUtil;
    private final MediatorConnection mediatorConnection;

    public UnsecureSourceSideConnectionEstablishment() throws Exception {
        this.registry = NATTraversalRegistryImpl.getInstance();
        this.selection = new ConnectionSetupTimeSelection(this.registry);
        this.investigator = new InfrastructureInvestigatorImpl();
        this.managerUtil = ManagerUtilImpl.getInstance();
        this.mediatorConnection = new MediatorConnection();
    }

    @Override
    public Socket establishConnection(final String targetId, final ConnectionConfiguration config) {
        final NATBehavior sourceNat = this.investigator.investigateOwnNat(this.mediatorConnection
                .getControlConnection().getLocalPort());
        NATBehavior targetNat;
        try {
            logger.debug("Requesting nat of {}", targetId); //$NON-NLS-1$
            targetNat = this.requestTargetNatBehavior(targetId);
        } catch (final Exception e) {
            logger.error(e.getMessage());
            targetNat = new NATBehavior();
        }
        final NATSituation natSituation = new NATSituation(sourceNat, targetNat);
        logger.debug("Current nat situation: {}", natSituation.toString()); //$NON-NLS-1$
        List<NATTraversalTechniqueAttribute> supportedTravTechsByTarget = new ArrayList<NATTraversalTechniqueAttribute>();
        try {
            logger.debug("Requesting supported nat traversal techniques of {}", targetId); // $NON-NLS-1$
            supportedTravTechsByTarget = this.requestSupportedTraversalTechniquesOfTarget(targetId);
        } catch (final Exception e1) {
            logger.error("Could not request supported nat traversal techniques of target", e1); //$NON-NLS-1$
        }
        logger.debug("Creating source-side connection"); // $NON-NLS-1$
        final Socket connectedSocket = this.createSourceSideConnection(targetId, natSituation,
                supportedTravTechsByTarget);
        try {
            this.managerUtil.setTrafficClass(connectedSocket, config);
        } catch (final Exception e) {
            this.logger
                    .error("Could not set service class {} for socket {}", config.getServiceClass(), connectedSocket); //$NON-NLS-1$
        }
        logger.debug("Connection established to {}", connectedSocket.toString()); // $NON-NLS-1$
        this.mediatorConnection.close();
        return connectedSocket;
    }

    private NATBehavior requestTargetNatBehavior(final String targetId) throws Exception {
        NATBehavior result = new NATBehavior();
        final Message requestMessage = MessageStaticFactory.newSTUNMessageInstance(STUNMessageClass.REQUEST,
                STUNMessageMethod.NAT_REQUEST);
        requestMessage.addAttribute(new Username(targetId));
        requestMessage.writeTo(this.mediatorConnection.getControlConnection().getOutputStream());
        final MessageReader messageReader = MessageReader
                .createMessageReaderWithCustomAttributeTypeDecoder(new NATAttributeTypeDecoder());
        final Message response = messageReader.readSTUNMessage(this.mediatorConnection.getControlConnection()
                .getInputStream());
        if (response.hasAttribute(NATBehavior.class)) {
            result = response.getAttribute(NATBehavior.class);
        }
        this.logger.debug("target {} is behind nat {}", targetId, result.toString()); //$NON-NLS-1$
        return result;
    }

    private List<NATTraversalTechniqueAttribute> requestSupportedTraversalTechniquesOfTarget(final String targetId)
            throws Exception {
        final List<NATTraversalTechniqueAttribute> result = new ArrayList<NATTraversalTechniqueAttribute>();
        final Message requestMessage = MessageStaticFactory.newSTUNMessageInstance(STUNMessageClass.REQUEST,
                STUNMessageMethod.SUPPORTED_TRAV_TECHS_REQUEST);
        requestMessage.addAttribute(new Username(targetId));
        requestMessage.writeTo(this.mediatorConnection.getControlConnection().getOutputStream());
        final MessageReader messageReader = MessageReader
                .createMessageReaderWithCustomAttributeTypeDecoder(new NATAttributeTypeDecoder());
        final Message response = messageReader.readSTUNMessage(this.mediatorConnection.getControlConnection()
                .getInputStream());
        if (response.hasAttribute(NATTraversalTechniqueAttribute.class)) {
            for (final NATTraversalTechniqueAttribute ntta : response
                    .getAttributes(NATTraversalTechniqueAttribute.class)) {
                result.add(ntta);
            }
        } else {
            logger.debug("No supported traversal techniques for {} returned.", targetId);
        }
        return Collections.unmodifiableList(result);
    }

    private Socket createSourceSideConnection(final String targetId, final NATSituation natSituation,
            final List<NATTraversalTechniqueAttribute> supportedTravTechsByTarget) {
        for (NATTraversalTechniqueAttribute supportedTravTechByTarget : supportedTravTechsByTarget) {
            logger.debug("target supports {}", supportedTravTechByTarget.getEncoded()); //$NON-NLS-1$
        }
        Socket resultSocket = null;
        final ExecutorService executor = Executors.newSingleThreadExecutor();
        final List<NATTraversalTechnique> traversalTechniques = this.selection
                .getNATTraversalTechniquesForNATSituation(natSituation);
        this.logger.debug("Current nat situation {}", natSituation.toString()); //$NON-NLS-1$
        this.logger.debug("Got the following traversal techniques in order"); //$NON-NLS-1$
        for (final NATTraversalTechnique natTraversalTechnique : traversalTechniques) {
            this.logger.debug(
                    "Appropriate technique: {}", natTraversalTechnique.getMetaData().getTraversalTechniqueName()); //$NON-NLS-1$
        }
        for (final NATTraversalTechnique natTraversalTechnique : traversalTechniques) {
            if (supportedTravTechsByTarget.contains(natTraversalTechnique.getMetaData().getAttribute())) {
                logger.debug("Trying to establish connection via {}", natTraversalTechnique.getMetaData()
                        .getTraversalTechniqueName());
                Future<Socket> future = null;
                try {
                    final Callable<Socket> socketTask = new SocketTask(targetId, natTraversalTechnique,
                            this.mediatorConnection.getControlConnection());
                    future = executor.submit(socketTask);
                    resultSocket = future.get(natTraversalTechnique.getMetaData().getTimeout(), TimeUnit.MILLISECONDS);
                } catch (final TimeoutException toe) {
                    this.logger.error("Timeout while creating source-side connection via {}.", natTraversalTechnique //$NON-NLS-1$
                            .getMetaData().getTraversalTechniqueName());
                    // do nothing, try next traversal technique
                } catch (final Exception e) {
                    this.logger.error(e.getMessage());
                } finally {
                    if (null != future) {
                        future.cancel(true);
                    }
                }
                if (resultSocket != null && resultSocket.isConnected()) {
                    break;
                }
            } else {
                logger.debug(
                        "{} is not supported by the target and not tried", natTraversalTechnique.getMetaData().getTraversalTechniqueName()); //$NON-NLS-1$
            }
        }
        executor.shutdownNow();
        return resultSocket;
    }
}
TOP

Related Classes of de.fhkn.in.uce.connectivitymanager.manager.source.UnsecureSourceSideConnectionEstablishment

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.