Package de.fhkn.in.uce.relaying

Source Code of de.fhkn.in.uce.relaying.Relaying

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

import java.io.IOException;
import java.net.Inet6Address;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.util.ResourceBundle;

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

import de.fhkn.in.uce.plugininterface.ConnectionNotEstablishedException;
import de.fhkn.in.uce.plugininterface.NATTraversalTechnique;
import de.fhkn.in.uce.plugininterface.NATTraversalTechniqueMetaData;
import de.fhkn.in.uce.relaying.core.RelayingClient;
import de.fhkn.in.uce.relaying.message.RelayingAttribute;
import de.fhkn.in.uce.stun.attribute.Username;
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;

/**
* Implementation of {@link NATTraversalTechnique} which realizes a indirect
* connection by using a relay server.
*
* @author Alexander Diener (aldiener@htwg-konstanz.de)
*
*/
public final class Relaying implements NATTraversalTechnique {
    private static final Logger logger = LoggerFactory.getLogger(Relaying.class);
    private static final String BUNDLE_NAME_RELAYING_PROPERTIES = "de.fhkn.in.uce.relaying.relaying"; //$NON-NLS-1$
    private final NATTraversalTechniqueMetaData metaData;
    private final InetSocketAddress relayAddress;
    private final ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_NAME_RELAYING_PROPERTIES);

    // private RelayingClient targetRelayClient = null;

    // private volatile boolean isRegistered = false;

    public Relaying() {
        try {
            this.metaData = new RelayingMetaData();
            this.relayAddress = this.getRelayServerAddressFromBundle();
        } catch (final Exception e) {
            logger.error("Exception occured while creating relaying connection object.", e); //$NON-NLS-1$
            throw new RuntimeException("Could not create relaying connection object.", e); //$NON-NLS-1$
        }
    }

    public Relaying(final Relaying toCopy) {
        try {
            this.metaData = new RelayingMetaData((RelayingMetaData) toCopy.getMetaData());
            this.relayAddress = toCopy.relayAddress;
        } catch (final Exception e) {
            logger.error("Exception occured while creating relaying connection object.", e); //$NON-NLS-1$
            throw new RuntimeException("Could not create relaying connection object.", e); //$NON-NLS-1$
        }
    }

    private InetSocketAddress getRelayServerAddressFromBundle() throws Exception {
        final String host = this.bundle.getString("relaying.server.ip"); //$NON-NLS-1$
        final String port = this.bundle.getString("relaying.server.port"); //$NON-NLS-1$
        return new InetSocketAddress(host, Integer.valueOf(port));
    }

    @Override
    public Socket createSourceSideConnection(final String targetId, final Socket controlConnection)
            throws ConnectionNotEstablishedException {
        try {
            this.sendConnectionRequest(targetId, controlConnection);
            final Message responseMessage = this.receiveConnectionResponse(controlConnection);
            final InetSocketAddress endpointAtRelayServer = this.getEndpointFromMessage(responseMessage);
            return this.connectToTargetEndpoint(endpointAtRelayServer);
        } catch (final Exception e) {
            logger.error(e.getMessage());
            throw new ConnectionNotEstablishedException(this.metaData.getTraversalTechniqueName(),
                    "Source-side socket could not be created.", e); //$NON-NLS-1$
        }
    }

    private void sendConnectionRequest(final String targetId, final Socket controlConnection) throws Exception {
        logger.debug("Sending connection request"); //$NON-NLS-1$
        final Message requestConnectionMessage = MessageStaticFactory.newSTUNMessageInstance(STUNMessageClass.REQUEST,
                STUNMessageMethod.CONNECTION_REQUEST);
        requestConnectionMessage.addAttribute(new Username(targetId));
        requestConnectionMessage.addAttribute(new RelayingAttribute());
        requestConnectionMessage.writeTo(controlConnection.getOutputStream());
    }

    private Message receiveConnectionResponse(final Socket controlConnection) throws IOException {
        final MessageReader messageReader = MessageReader.createMessageReader();
        return messageReader.readSTUNMessage(controlConnection.getInputStream());
    }

    private InetSocketAddress getEndpointFromMessage(final Message msg) throws Exception {
        InetSocketAddress result = null;
        if (msg.hasAttribute(XorMappedAddress.class)) {
            result = msg.getAttribute(XorMappedAddress.class).getEndpoint();
        } else {
            final String errorMessage = "The target endpoint at relay is not returned by the mediator."; //$NON-NLS-1$
            logger.debug(errorMessage);
            throw new ConnectionNotEstablishedException(this.metaData.getTraversalTechniqueName(), errorMessage, null);
        }
        return result;
    }

    private Socket connectToTargetEndpoint(final InetSocketAddress endpoint) throws Exception {
        final Socket socket = new Socket();
        socket.setReuseAddress(true);
        socket.connect(endpoint, endpoint.getPort());
        return socket;
    }

    @Override
    public Socket createTargetSideConnection(final String targetId, final Socket controlConnection,
            final Message connectioRequestMessage) throws ConnectionNotEstablishedException {
        Socket socket = new Socket();
        try {
            final RelayingClient targetRelayClient = new RelayingClient(this.relayAddress);
            final InetSocketAddress endpointAtRelay = this.createAllocationAtRelayServer(targetRelayClient);
            logger.debug("Allocation at relay server created: {}", endpointAtRelay.toString());
            this.sendConnectionRequestResponse(controlConnection, connectioRequestMessage, endpointAtRelay);
            socket = targetRelayClient.accept();
        } catch (final Exception e) {
            logger.error(e.getMessage());
            throw new ConnectionNotEstablishedException(this.metaData.getTraversalTechniqueName(),
                    "Could not create target-side conenction.", e); //$NON-NLS-1$
        }
        return socket;
    }

    private void sendConnectionRequestResponse(final Socket controlConnection, final Message connectionRequest,
            final InetSocketAddress endpointAtRelay) throws IOException {
        final Message response = connectionRequest.buildSuccessResponse();
        response.addAttribute(new RelayingAttribute());
        XorMappedAddress endpointAtRelayAttribute;
        if (endpointAtRelay.getAddress() instanceof Inet6Address) {
            endpointAtRelayAttribute = new XorMappedAddress(endpointAtRelay, ByteBuffer.wrap(
                    response.getHeader().getTransactionId()).getInt());
        } else {
            endpointAtRelayAttribute = new XorMappedAddress(endpointAtRelay);
        }
        response.addAttribute(endpointAtRelayAttribute);
        response.writeTo(controlConnection.getOutputStream());
    }

    @Override
    public void registerTargetAtMediator(final String targetId, final Socket controlConnection) throws Exception {
        // can be used to use traversal technique without connectivity manager
    }

    private InetSocketAddress createAllocationAtRelayServer(final RelayingClient relayingClient) throws Exception {
        logger.debug("Creating allocation at relay server");
        InetSocketAddress result = relayingClient.createAllocation();
        if (result.getAddress().isAnyLocalAddress()) {
            result = new InetSocketAddress(this.relayAddress.getAddress(), result.getPort());
        }
        logger.debug("Allocation at relay server created: {}", result.toString());
        return result;
    }

    @Override
    public void deregisterTargetAtMediator(final String targetId, final Socket controlConnection) throws Exception {
        // can be used to use traversal technique without connectivity manager
    }

    @Override
    public NATTraversalTechniqueMetaData getMetaData() {
        return this.metaData;
    }

    @Override
    public NATTraversalTechnique copy() {
        return new Relaying(this);
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((this.metaData == null) ? 0 : this.metaData.hashCode());
        return result;
    }

    @Override
    public boolean equals(final Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (this.getClass() != obj.getClass()) {
            return false;
        }
        final Relaying other = (Relaying) obj;
        if (this.metaData == null) {
            if (other.metaData != null) {
                return false;
            }
        } else if (!this.metaData.equals(other.metaData)) {
            return false;
        }
        return true;
    }
}
TOP

Related Classes of de.fhkn.in.uce.relaying.Relaying

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.