Package de.fhkn.in.uce.connectivitymanager.mediatorconnection

Source Code of de.fhkn.in.uce.connectivitymanager.mediatorconnection.MediatorConnection

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

import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.ResourceBundle;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

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

import de.fhkn.in.uce.core.KeepAliveTask;
import de.fhkn.in.uce.plugininterface.NATBehavior;
import de.fhkn.in.uce.plugininterface.message.NATTraversalTechniqueAttribute;
import de.fhkn.in.uce.stun.attribute.ErrorCode;
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;

/**
* Connection to the mediator. Provides functionality which is used to
* communicate with it.
*
* @author Alexander Diener (aldiener@htwg-konstanz.de)
*
*/
public final class MediatorConnection {
    private static final String PROPERTY_NAME_MEDIATOR = "mediator"; //$NON-NLS-1$
    private static final String PROPERTY_NAME_IP = "ip"; //$NON-NLS-1$
    private static final String PROPERTY_NAME_PORT = "port"; //$NON-NLS-1$
    private static final String PROPERTY_NAME_KEEP_ALIVE = "keepalive"; //$NON-NLS-1$
    private static final String SEPARATOR = "."; //$NON-NLS-1$
    private final Logger logger = LoggerFactory.getLogger(MediatorConnection.class);
    private final ResourceBundle bundle = ResourceBundle
            .getBundle("de.fhkn.in.uce.connectivitymanager.mediatorconnection.mediator"); //$NON-NLS-1$
    private final Socket controlConnection;
    private final MessageReader messageReader;
    private final ScheduledExecutorService keepAliveExecutor;

    /**
     * Creates a mediator connection and connects to the mediator address in the
     * property file.
     *
     * @param mediatorAddress
     * @throws Exception
     */
    public MediatorConnection() throws Exception {
        this.messageReader = MessageReader.createMessageReader();
        this.keepAliveExecutor = Executors.newScheduledThreadPool(1);
        final InetSocketAddress mediatorAddress = this.getMediatorAddress();
        this.controlConnection = new Socket();
        this.controlConnection.setReuseAddress(true);
        logger.debug("connecting to mediator {}", mediatorAddress.toString());
        this.controlConnection.connect(mediatorAddress);
    }

    /**
     * Sends a register message for the given target id and NAT situation of the
     * target. Also starts a keep alive thread for the registration.
     *
     * @param targetId
     *            the unique name of the target
     * @param currentNatBehavior
     *            the {@link NATBehavior} of the target
     * @param delayInSecondsForKeepAlive
     *            the time in seconds which is used to send keep alive messages
     * @throws Exception
     */
    public void registerTarget(final String targetId, final NATBehavior currentNatBehavior,
            final List<NATTraversalTechniqueAttribute> supportedTraversalTechniques) throws Exception {
        this.sendRegisterMessage(targetId, currentNatBehavior, supportedTraversalTechniques);
        this.waitForDeRegisterResponseMessage();
        this.startKeepAlive(targetId, this.getKeepAliveInSeconds());
    }

    private void sendRegisterMessage(final String targetId, final NATBehavior natBehavior,
            final List<NATTraversalTechniqueAttribute> supportedTraversalTechniques) throws Exception {
        final Message registerMessage = MessageStaticFactory.newSTUNMessageInstance(STUNMessageClass.REQUEST,
                STUNMessageMethod.REGISTER);
        registerMessage.addAttribute(new Username(targetId));
        registerMessage.addAttribute(natBehavior);
        for (final NATTraversalTechniqueAttribute natTraversalTechniqueAttribute : supportedTraversalTechniques) {
            registerMessage.addAttribute(natTraversalTechniqueAttribute);
        }
        registerMessage.writeTo(this.controlConnection.getOutputStream());
    }

    private void waitForDeRegisterResponseMessage() throws Exception {
        final Message response = this.messageReader.readSTUNMessage(this.controlConnection.getInputStream());
        if (response.isSuccessResponse()) {
            this.logger.debug("Target successfully (de)registered"); //$NON-NLS-1$
        } else {
            final ErrorCode errorCode = response.getAttribute(ErrorCode.class);
            final String errorMessage = "Could not (de)register target: " + errorCode.getErrorNumber() + " " + errorCode.getReasonPhrase(); //$NON-NLS-1$ //$NON-NLS-2$
            throw new Exception(errorMessage);
        }
    }

    private void startKeepAlive(final String targetId, final int delayInSeconds) {
        final Runnable keepAliveTask = new KeepAliveTask(targetId, this.controlConnection);
        this.keepAliveExecutor.scheduleWithFixedDelay(keepAliveTask, delayInSeconds, delayInSeconds, TimeUnit.SECONDS);
    }

    /**
     * Send a deregister message and stops the task for sending keep alive
     * messages.
     *
     * @param targetId
     *            the unique name of the target
     * @throws Exception
     */
    public void deregisterTarget(final String targetId) throws Exception {
        this.sendDeregisterMesage(targetId);
        this.waitForDeRegisterResponseMessage();
        this.keepAliveExecutor.shutdownNow();
    }

    private void sendDeregisterMesage(final String targetId) throws Exception {
        final Message deregisterMessage = MessageStaticFactory.newSTUNMessageInstance(STUNMessageClass.REQUEST,
                STUNMessageMethod.DEREGISTER);
        deregisterMessage.addAttribute(new Username(targetId));
        deregisterMessage.writeTo(this.controlConnection.getOutputStream());
    }

    /**
     * Returns the control connection to the mediator.
     *
     * @return the control connection to the mediator
     */
    public Socket getControlConnection() {
        return this.controlConnection;
    }

    private InetSocketAddress getMediatorAddress() {
        final String mediatorIP = this.bundle.getString(PROPERTY_NAME_MEDIATOR + SEPARATOR + PROPERTY_NAME_IP);
        final int mediatorPort = Integer.valueOf(this.bundle.getString(PROPERTY_NAME_MEDIATOR + SEPARATOR
                + PROPERTY_NAME_PORT));
        return new InetSocketAddress(mediatorIP, mediatorPort);
    }

    private int getKeepAliveInSeconds() {
        return Integer.valueOf(this.bundle.getString(PROPERTY_NAME_MEDIATOR + SEPARATOR + PROPERTY_NAME_KEEP_ALIVE));
    }

    /**
     * Sends a request for getting the supported NAT traversal techniques of a
     * user to the mediator. The result is returned as a unmodifiable list of
     * {@link NATTraversalTechniqueAttribute}s.
     *
     * @param targetId
     *            the id of the user
     * @return the supported NAT traversal techniques of the user as a list of
     *         {@link NATTraversalTechniqueAttribute}s
     * @throws Exception
     */
    public List<NATTraversalTechniqueAttribute> requestSupportedTraversalTechniques(final String targetId)
            throws Exception {
        this.logger.debug("Requesting supported nat traversal techniques of {}", targetId); //$NON-NLS-1$
        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.controlConnection.getOutputStream());
        final Message response = this.messageReader.readSTUNMessage(this.controlConnection.getInputStream());
        for (final NATTraversalTechniqueAttribute suppTravTech : response
                .getAttributes(NATTraversalTechniqueAttribute.class)) {
            result.add(suppTravTech);
            this.logger.debug("User {} supports traversal technique {}", targetId, suppTravTech.getEncoded()); //$NON-NLS-1$
        }
        return Collections.unmodifiableList(result);
    }

    /**
     * Closes the mediator connection and cancels the keep alive task. But this
     * method does not sends a deregister message to the mediator.
     */
    public void close() {
        try {
            this.keepAliveExecutor.shutdownNow();
            this.controlConnection.close();
        } catch (final Exception e) {
            logger.error(e.getMessage());
        }
    }
}
TOP

Related Classes of de.fhkn.in.uce.connectivitymanager.mediatorconnection.MediatorConnection

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.