All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.restcomm.media.control.mgcp.controller.MgcpController Maven / Gradle / Ivy

There is a newer version: 7.0.16
Show newest version
/*
 * TeleStax, Open Source Cloud Communications
 * Copyright 2011-2016, Telestax Inc and individual contributors
 * by the @authors tag. 
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

package org.restcomm.media.control.mgcp.controller;

import java.net.InetSocketAddress;

import org.apache.log4j.Logger;
import org.restcomm.media.control.mgcp.command.MgcpCommand;
import org.restcomm.media.control.mgcp.command.MgcpCommandProvider;
import org.restcomm.media.control.mgcp.controller.fsm.MgcpControllerEvent;
import org.restcomm.media.control.mgcp.controller.fsm.MgcpControllerFsm;
import org.restcomm.media.control.mgcp.controller.fsm.MgcpControllerFsmBuilder;
import org.restcomm.media.control.mgcp.controller.fsm.MgcpControllerFsmImpl;
import org.restcomm.media.control.mgcp.controller.fsm.MgcpControllerGlobalContext;
import org.restcomm.media.control.mgcp.controller.fsm.MgcpControllerState;
import org.restcomm.media.control.mgcp.endpoint.MgcpEndpointManager;
import org.restcomm.media.control.mgcp.exception.DuplicateMgcpTransactionException;
import org.restcomm.media.control.mgcp.exception.MgcpTransactionNotFoundException;
import org.restcomm.media.control.mgcp.message.MessageDirection;
import org.restcomm.media.control.mgcp.message.MgcpMessage;
import org.restcomm.media.control.mgcp.message.MgcpMessageObserver;
import org.restcomm.media.control.mgcp.message.MgcpRequest;
import org.restcomm.media.control.mgcp.message.MgcpResponse;
import org.restcomm.media.control.mgcp.message.MgcpResponseCode;
import org.restcomm.media.control.mgcp.network.netty.AsyncMgcpChannel;
import org.restcomm.media.control.mgcp.transaction.MgcpTransactionManager;
import org.restcomm.media.spi.ControlProtocol;
import org.restcomm.media.spi.Endpoint;
import org.restcomm.media.spi.EndpointInstaller;
import org.restcomm.media.spi.ServerManager;

import com.google.common.util.concurrent.FutureCallback;

/**
 * @author Henrique Rosa ([email protected])
 *
 */
public class MgcpController implements ServerManager, MgcpMessageObserver {

    private static final Logger log = Logger.getLogger(MgcpController.class);

    // MGCP Components
    private final MgcpTransactionManager transactions;
    private final MgcpEndpointManager endpoints;
    private final MgcpCommandProvider commands;

    // MGCP Controller State
    private final MgcpControllerGlobalContext context;
    private final MgcpControllerFsm fsm;

    public MgcpController(String address, int port, AsyncMgcpChannel channel, MgcpTransactionManager transactions, MgcpEndpointManager endpoints, MgcpCommandProvider commands) {
        // MGCP Components
        this.transactions = transactions;
        this.endpoints = endpoints;
        this.commands = commands;

        // MGCP Controller State
        this.context = new MgcpControllerGlobalContext();
        this.context.setBindAddress(new InetSocketAddress(address, port));
        this.context.setChannel(channel);
        this.fsm = MgcpControllerFsmBuilder.INSTANCE.build(this.context);
        this.fsm.start();
    }

    @Override
    public ControlProtocol getControlProtocol() {
        return ControlProtocol.MGPC;
    }

    @Override
    public void activate() throws IllegalStateException {
        if (isActive()) {
            throw new IllegalStateException("Controller is already active");
        } else {
            this.context.getChannel().observe(this);
            this.transactions.observe(this);
            this.endpoints.observe(this);

            this.fsm.fire(MgcpControllerEvent.ACTIVATE);
        }
    }

    @Override
    public void deactivate() throws IllegalStateException {
        if (isActive()) {
            // TODO elegant cleanup of existing resources
            this.context.getChannel().forget(this);
            this.transactions.forget(this);
            this.endpoints.observe(this);

            this.fsm.fire(MgcpControllerEvent.DEACTIVATE);
        } else {
            throw new IllegalStateException("Controller is already inactive");
        }
    }

    @Override
    public boolean isActive() {
        return MgcpControllerState.ACTIVATED.equals(this.fsm.getCurrentState());
    }

    @Override
    public void onStarted(Endpoint endpoint, EndpointInstaller installer) {
        // Legacy stuff
    }

    @Override
    public void onStopped(Endpoint endpoint) {
        // Legacy stuff
    }

    @Override
    public void onMessage(InetSocketAddress from, InetSocketAddress to, MgcpMessage message, MessageDirection direction) {
        switch (direction) {
            case INCOMING:
                if (message.isRequest()) {
                    onIncomingRequest(from, to, (MgcpRequest) message);
                } else {
                    onIncomingResponse(from, to, (MgcpResponse) message);
                }
                break;

            case OUTGOING:
                if (message.isRequest()) {
                    onOutgoingRequest(from, to, (MgcpRequest) message);
                } else {
                    onOutgoingResponse(from, to, (MgcpResponse) message);
                }
                break;

            default:
                throw new IllegalArgumentException("Unknown message direction: " + direction.name());
        }
    }

    private void onIncomingRequest(InetSocketAddress from, InetSocketAddress to, MgcpRequest request) {
        // Get command to be executed
        MgcpCommand command = this.commands.provide(request.getRequestType(), request.getTransactionId(),
                request.getParameters());

        try {
            // Start transaction that will execute the command
            this.transactions.process(from, to, request, command, MessageDirection.INCOMING);
        } catch (DuplicateMgcpTransactionException e) {
            // Transaction is already being processed
            // Send provisional message
            MgcpResponseCode provisional = MgcpResponseCode.TRANSACTION_BEING_EXECUTED;

            if (log.isDebugEnabled()) {
                log.debug("Received duplicate request tx=" + request.getTransactionId() + " from " + from.toString()
                        + ". Sending provisional response with code " + provisional.code());
            }

            sendResponse(to, request.getTransactionId(), provisional.code(), provisional.message());
        }
    }

    private void onOutgoingRequest(InetSocketAddress from, InetSocketAddress to, MgcpRequest request) {
        try {
            // Start transaction
            this.transactions.process(from, to, request, null, MessageDirection.OUTGOING);
            // Send request to call agent
            this.context.getChannel().send(request, to, new SendChannelCallback());
        } catch (DuplicateMgcpTransactionException e) {
            log.error(e.getMessage() + ". Request wont' be sent to call agent.");
        }
    }

    private void onIncomingResponse(InetSocketAddress from, InetSocketAddress to, MgcpResponse response) {
        try {
            // Close transaction
            this.transactions.process(from, to, response, MessageDirection.INCOMING);
        } catch (MgcpTransactionNotFoundException e) {
            log.error(e.getMessage());
        }
    }

    private void onOutgoingResponse(InetSocketAddress from, InetSocketAddress to, MgcpResponse response) {
        try {
            // Close transaction
            this.transactions.process(from, to, response, MessageDirection.OUTGOING);
            // Send response to call agent
            this.context.getChannel().send(response, to, new SendChannelCallback());
        } catch (MgcpTransactionNotFoundException e) {
            log.error(e.getMessage() + ". Response won't be sent to call agent.");
        }
    }

    private void sendResponse(InetSocketAddress to, int transactionId, int code, String message) {
        MgcpResponse response = new MgcpResponse();
        response.setTransactionId(transactionId);
        response.setCode(code);
        response.setMessage(message);
        this.context.getChannel().send(response, to, new SendChannelCallback());
    }
    
    private class SendChannelCallback implements FutureCallback {

        @Override
        public void onSuccess(Void result) {
            // TODO Auto-generated method stub
            
        }

        @Override
        public void onFailure(Throwable t) {
            log.warn("Could not send MGCP message to remote peer.", t);
            
        }}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy