Package de.fhkn.in.uce.relaying.server

Source Code of de.fhkn.in.uce.relaying.server.RelayAllocationHandler

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

import java.io.IOException;
import java.net.BindException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

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

import de.fhkn.in.uce.core.socketlistener.SocketListener;
import de.fhkn.in.uce.relaying.message.RelayingLifetime;
import de.fhkn.in.uce.stun.attribute.EndpointClass;
import de.fhkn.in.uce.stun.attribute.EndpointClass.EndpointCategory;
import de.fhkn.in.uce.stun.attribute.ErrorCode.STUNErrorCode;
import de.fhkn.in.uce.stun.attribute.XorMappedAddress;
import de.fhkn.in.uce.stun.message.Message;
import de.fhkn.in.uce.stun.message.MessageWriter;

/**
* Class to handle allocation requests from clients.
*
* @author thomas zink, daniel maier, Alexander Diener
*         (aldiener@htwg-konstanz.de)
*
*/
final class RelayAllocationHandler {
    private static final Logger logger = LoggerFactory.getLogger(RelayAllocationHandler.class);
    public static final int MIN_PORT = 10150;
    public static final int MAX_PORT = 10160;

    private final Socket controlConnection;
    private final MessageWriter controlConnectionWriter;
    private final Map<UUID, BlockingQueue<Socket>> connIDToQueue;
    private final Message relayAllocationMessage;
    // has to be unbounded
    private final Executor controlConnectionHandlerExecutor;
    // has to be unbounded
    private final Executor relayExecutor;

    /**
     * Creates a new {@link RelayAllocationHandler}.
     *
     * @param controlConnection
     *            the socket of the control connection to the client
     * @param controlConnectionWriter
     *            a {@link MessageWriter} to the control connection
     * @param connIDToQueue
     *            map to match relay connection between client and peers
     * @param relayAllocationMessage
     *            the allocation request message
     * @param controlConnectionHandlerExecutor
     *            the executor that gets used to execute the
     *            {@link RefreshMessageHandlerTask} for the given control
     *            connection
     * @param relayExecutor
     *            the executor that gets used to execute task for the real relay
     *            stuff
     */
    public RelayAllocationHandler(Socket controlConnection, MessageWriter controlConnectionWriter,
            Map<UUID, BlockingQueue<Socket>> connIDToQueue, Message relayAllocationMessage,
            Executor controlConnectionHandlerExecutor, Executor relayExecutor) {
        this.controlConnection = controlConnection;
        this.controlConnectionWriter = controlConnectionWriter;
        this.connIDToQueue = connIDToQueue;
        this.relayAllocationMessage = relayAllocationMessage;
        this.controlConnectionHandlerExecutor = controlConnectionHandlerExecutor;
        this.relayExecutor = relayExecutor;
    }

    /**
     * Handles the allocation request message. Creates a new ServerSocket and
     * listener thread to handle connection requests from peers. If there is no
     * free port available in the specified port range, an
     * "Insufficient Capacity" error is returned to the client.
     */
    public void handle() {
        try {
            // get Lifetime
            int lifetime = 0;
            if (relayAllocationMessage.hasAttribute(RelayingLifetime.class)) {
                lifetime = relayAllocationMessage.getAttribute(RelayingLifetime.class).getLifeTime();
            }
            // Create ServerSocket for peers
            ServerSocket peerSS = createServerSocketWithinPortRange();
            if (peerSS == null) {
                logger.info("Insufficient Capacity");
                Message errorResponse = relayAllocationMessage.buildFailureResponse(
                        STUNErrorCode.INSUFFICIENT_CAPACITY, "Insufficient Capacity");
                controlConnectionWriter.writeMessage(errorResponse);
            } else {
                // TODO listener tasks in threadpool, listener also in pool?
                logger.info("Created allocation on {}", peerSS.getLocalSocketAddress());
                SocketListener peerSocketListener = new SocketListener(peerSS, Executors.newCachedThreadPool(),
                        new PeerHandlerTaskFactory(connIDToQueue, controlConnectionWriter, relayExecutor));
                controlConnectionHandlerExecutor.execute(new RefreshMessageHandlerTask(controlConnection,
                        controlConnectionWriter, lifetime, peerSocketListener));
                peerSocketListener.start();
                Message successResponse = relayAllocationMessage.buildSuccessResponse();
                successResponse.addAttribute(new XorMappedAddress(new InetSocketAddress(peerSS.getInetAddress(), peerSS
                        .getLocalPort())));
                successResponse.addAttribute(new EndpointClass(EndpointCategory.RELAY));
                successResponse.addAttribute(new RelayingLifetime(lifetime));
                controlConnectionWriter.writeMessage(successResponse);
            }
        } catch (IOException e) {
            logger.error("IOException while handling allocation request: {}", e);
        }
    }

    /**
     * Tries to to create and bind a new ServerSocket in the specified port
     * range.
     *
     * @return a new and bound ServerSocket, or null if no ServerSocket could be
     *         bounded in the specified port range.
     * @throws IOException
     *             if an I/O error occurs when opening the socket.
     */
    private ServerSocket createServerSocketWithinPortRange() throws IOException {
        int port = MIN_PORT;
        do {
            try {
                return new ServerSocket(port);
            } catch (BindException be) {
                port++;
            }
        } while (port <= MAX_PORT);
        return null;
    }
}
TOP

Related Classes of de.fhkn.in.uce.relaying.server.RelayAllocationHandler

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.