Package de.fhkn.in.uce.holepunching.core.target

Source Code of de.fhkn.in.uce.holepunching.core.target.HolePunchingTarget

/*
* 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.holepunching.core.target;

import java.io.IOException;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

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

import de.fhkn.in.uce.core.concurrent.ThreadGroupThreadFactory;
import de.fhkn.in.uce.holepunching.core.HolePuncher;
import de.fhkn.in.uce.stun.attribute.Token;
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;
import de.fhkn.in.uce.stun.message.MessageWriter;

/**
* Implementation of hole punching target for parallel hole punching. It
* consists of a task that is listening for forward endpoints messages and
* keep-live messages from the mediator. If a forward endpoints message arrives
* it starts tries to establish a connection to the hole punching source with
* the help of {@link HolePuncher}.
*
* @author Daniel Maier, Alexander Diener (aldiener@htwg-konstanz.de)
*
*/
public final class HolePunchingTarget {
    private static final Logger logger = LoggerFactory.getLogger(HolePunchingTarget.class);
    // private final SocketAddress mediatorSocketAddress;
    private final String targetId;
    private final BlockingQueue<Socket> socketQueue;
    private final ThreadGroupThreadFactory threadFactory;
    private Socket socketToMediator;
    private boolean started;
    private MessageHandlerTask messageHandlerTask;

    /**
     * Creates a new HolePunchingTarget.
     *
     * @param mediatorSocketAddress
     *            endpoint of the mediator on that it listens for registration
     *            messages.
     * @param registrationId
     *            the ID under that the target should get registered.
     */
    public HolePunchingTarget(final Socket controlConnection, final String targetId) {
        // this.mediatorSocketAddress = mediatorSocketAddress;
        this.socketToMediator = controlConnection;
        this.targetId = targetId;
        this.socketQueue = new LinkedBlockingQueue<Socket>();
        this.threadFactory = new ThreadGroupThreadFactory();
        this.started = false;
    }

    /**
     * Starts the HolePunchingTarget. Strictly speaking it starts the
     * {@link MessageHandlerTask} after it has registered the target with the
     * mediator. It can be started only one time.
     *
     * @throws IOException
     *             if an I/O error occurs while registering with the mediator.
     * @throws IllegalStateException
     *             if the target was already started.
     */
    public synchronized void start(final Message connectionRequestMessage) throws IOException, IllegalStateException {
        if (this.started) {
            throw new IllegalStateException("Target is already started"); //$NON-NLS-1$
        }
        this.started = true;
        final List<XorMappedAddress> endpoints = connectionRequestMessage.getAttributes(XorMappedAddress.class);
        final Token authentificationToken = connectionRequestMessage.getAttribute(Token.class);
        this.startMessageHandler(endpoints, authentificationToken);
    }

    @SuppressWarnings("unused")
    private void sendRegisterMessage() throws IOException {
        final Message registerMessage = MessageStaticFactory.newSTUNMessageInstance(STUNMessageClass.REQUEST,
                STUNMessageMethod.REGISTER);
        // target id
        registerMessage.addAttribute(new Username(this.targetId));
        // private endpoint
        final InetAddress privateAddress = this.socketToMediator.getLocalAddress();
        if (privateAddress instanceof Inet6Address) {
            registerMessage.addAttribute(new XorMappedAddress(new InetSocketAddress(this.socketToMediator
                    .getLocalAddress(), this.socketToMediator.getLocalPort()), ByteBuffer.wrap(
                    registerMessage.getHeader().getTransactionId()).getInt()));
        } else {
            registerMessage.addAttribute(new XorMappedAddress(new InetSocketAddress(this.socketToMediator
                    .getLocalAddress(), this.socketToMediator.getLocalPort())));
        }
        final MessageWriter messageWriter = new MessageWriter(this.socketToMediator.getOutputStream());
        logger.info("Sending RegisterMessage for {}", this.targetId); //$NON-NLS-1$
        messageWriter.writeMessage(registerMessage);
    }

    @SuppressWarnings("unused")
    private Message receiveMessage() throws IOException {
        final MessageReader messageReader = MessageReader.createMessageReader();
        return messageReader.readSTUNMessage(this.socketToMediator.getInputStream());
    }

    private void startMessageHandler(final List<XorMappedAddress> endpoints, final Token authentificationToken) {
        logger.debug("Starting message handler task"); //$NON-NLS-1$
        this.messageHandlerTask = new MessageHandlerTask(this.socketToMediator, this.socketQueue, 0, endpoints,
                authentificationToken);
        this.threadFactory.newThread(this.messageHandlerTask).start();
    }

    /**
     * Stops the HolePunchingTarget. Strictly speaking it sends an
     * {@link UnregisterMessage} over a new socket connection to the mediator
     * and then closes the both connections to it. Then it stops the
     * {@link MessageHandlerTask}.
     *
     * @throws IOException
     *             if an I/O error occurs while sending
     *             {@link UnregisterMessage} to mediator or when closing the
     *             socket to it.
     * @throws IllegalStateException
     *             if the target was not started yet.
     */
    public synchronized void stop() throws IOException, IllegalStateException {
        if (!this.started) {
            throw new IllegalStateException("Target is not started"); //$NON-NLS-1$
        }
        this.socketToMediator.close();
        this.messageHandlerTask.cancel();
    }

    /**
     * Returns a socket thats connection is established via hole-punching to
     * this target. The method blocks until a connection is made.
     *
     * @return the new socket.
     * @throws IOException
     *             if an I/O error occurs when waiting for a connection.
     * @throws InterruptedException
     *             if the current thread gets interrupted while blocked in
     *             accept().
     */
    // TODO irgendwie io exceptions aus ForwardEndpointsHandlerThread
    // weitergeben
    public Socket accept() throws IOException, InterruptedException {
        try {
            final Socket s = this.socketQueue.take();
            logger.info("Accepting socket: {}", s); //$NON-NLS-1$
            // received dummy socket for indicating time limit exceeded
            if (!s.isConnected()) {
                throw new IOException("IOException while accepting socket"); //$NON-NLS-1$
            }
            return s;
        } catch (final InterruptedException e) {
            Thread.currentThread().interrupt();
            throw e;
        }

    }
}
TOP

Related Classes of de.fhkn.in.uce.holepunching.core.target.HolePunchingTarget

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.