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

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

There is a newer version: 6.0.23
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.mobicents.media.control.mgcp.controller;

import java.io.IOException;
import java.net.InetSocketAddress;

import org.apache.log4j.Logger;
import org.mobicents.media.control.mgcp.command.MgcpCommand;
import org.mobicents.media.control.mgcp.command.MgcpCommandProvider;
import org.mobicents.media.control.mgcp.endpoint.MgcpEndpointManager;
import org.mobicents.media.control.mgcp.exception.DuplicateMgcpTransactionException;
import org.mobicents.media.control.mgcp.exception.MgcpTransactionNotFoundException;
import org.mobicents.media.control.mgcp.message.MessageDirection;
import org.mobicents.media.control.mgcp.message.MgcpMessage;
import org.mobicents.media.control.mgcp.message.MgcpMessageObserver;
import org.mobicents.media.control.mgcp.message.MgcpRequest;
import org.mobicents.media.control.mgcp.message.MgcpResponse;
import org.mobicents.media.control.mgcp.message.MgcpResponseCode;
import org.mobicents.media.control.mgcp.network.MgcpChannel;
import org.mobicents.media.control.mgcp.transaction.MgcpTransactionManager;
import org.mobicents.media.server.io.network.UdpManager;
import org.mobicents.media.server.spi.ControlProtocol;
import org.mobicents.media.server.spi.Endpoint;
import org.mobicents.media.server.spi.EndpointInstaller;
import org.mobicents.media.server.spi.ServerManager;

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

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

    // Core Components
    private final UdpManager networkManager;
    
    // MGCP Components
    private final MgcpChannel channel;
    private final MgcpTransactionManager transactions;
    private final MgcpEndpointManager endpoints;
    private final MgcpCommandProvider commands;

    // MGCP Controller State
    private final String address;
    private final int port;
    private boolean active;

    public MgcpController(String address, int port, UdpManager networkManager, MgcpChannel channel, MgcpTransactionManager transactions, MgcpEndpointManager endpoints, MgcpCommandProvider commands) {
        // Core Components
        this.networkManager = networkManager;

        // MGCP Components
        this.channel = channel;
        this.transactions = transactions;
        this.endpoints = endpoints;
        this.commands = commands;

        // MGCP Controller State
        this.address = address;
        this.port = port;
        this.active = false;
    }

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

    @Override
    public void activate() throws IllegalStateException {
        if (this.active) {
            throw new IllegalStateException("Controller is already active");
        } else {
            try {
                // Open MGCP channel and bind it to configured address
                this.channel.open();
                this.channel.bind(new InetSocketAddress(this.address, this.port));

                if (log.isInfoEnabled()) {
                    log.info("Opened MGCP channel at " + this.address + ":" + this.port);
                }
                
                // Register channel to network manager for multiplexing purposes
                this.networkManager.register(this.channel);

                // Register as observer to other components to receive notifications
                this.channel.observe(this);
                this.transactions.observe(this);
                this.endpoints.observe(this);
                this.active = true;
                
                if (log.isInfoEnabled()) {
                    log.info("MGCP controller is active");
                }
            } catch (IOException e) {
                log.error("An error occurred while activating the controller. Aborting.", e);
                // TODO cleanup
            }
        }
    }

    @Override
    public void deactivate() throws IllegalStateException {
        if (this.active) {
            // TODO stop resources
            this.channel.close();
            this.channel.forget(this);
            
            if (log.isInfoEnabled()) {
                log.info("MGCP channel is closed");
            }
            
            this.transactions.forget(this);
            this.endpoints.forget(this);
            // TODO clear transactions
            this.active = false;
            
            if (log.isInfoEnabled()) {
                log.info("MGCP controller is inactive");
            }
        } else {
            throw new IllegalStateException("Controller is already inactive");
        }
    }

    @Override
    public boolean isActive() {
        return this.active;
    }

    @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());
            }

            try {
                sendResponse(to, request.getTransactionId(), provisional.code(), provisional.message());
            } catch (IOException e1) {
                log.error("Could not send provisional response to call agent, regarding transaction " + request.getTransactionId(), e);
            }
        }
    }

    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.channel.send(to, request);
        } catch (DuplicateMgcpTransactionException e) {
            log.error(e.getMessage() + ". Request wont' be sent to call agent.");
        } catch (IOException e) {
            log.error("Could not send MGCP request to call agent: " + request.toString(), e);
        }
    }

    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.channel.send(to, response);
        } catch (MgcpTransactionNotFoundException e) {
            log.error(e.getMessage() + ". Response won't be sent to call agent.");
        } catch (IOException e) {
            log.error("Could not send MGCP response to call agent: " + response.toString(), e);
        }
    }

    private void sendResponse(InetSocketAddress to, int transactionId, int code, String message) throws IOException {
        MgcpResponse response = new MgcpResponse();
        response.setTransactionId(transactionId);
        response.setCode(code);
        response.setMessage(message);
        this.channel.send(to, response);
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy