Package com.ericsson.ssa.container

Source Code of com.ericsson.ssa.container.MessageProcessorFilter

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
* Copyright (c) Ericsson AB, 2004-2008. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code.  If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.ericsson.ssa.container;

import com.ericsson.ssa.container.startup.SipMonitoring;
import com.ericsson.ssa.sip.Header;
import com.ericsson.ssa.sip.Layer;
import com.ericsson.ssa.sip.LayerHelper;
import com.ericsson.ssa.sip.SipParser;
import com.ericsson.ssa.sip.SipServletMessageImpl;

//import com.ericsson.ssa.sip.SipServletMessageImpl.SipMessageType;
import com.ericsson.ssa.sip.SipServletRequestImpl;
import com.ericsson.ssa.sip.SipServletResponseImpl;
import com.ericsson.ssa.sip.dns.SipTransports;
import com.ericsson.ssa.sip.dns.TargetResolver;
import com.ericsson.ssa.sip.dns.TargetTuple;
import com.ericsson.ssa.utils.ByteBufferPool;

import com.sun.grizzly.Context;
import com.sun.grizzly.Controller.Protocol;
import com.sun.grizzly.ProtocolFilter;
import com.sun.grizzly.SelectorHandler;
import com.sun.grizzly.TCPSelectorHandler;
import com.sun.grizzly.async.AsyncWriteCallbackHandler;
import com.sun.grizzly.filter.ReadFilter;
import com.sun.grizzly.util.ByteBufferInputStream;
import com.sun.grizzly.util.WorkerThread;
import com.sun.grizzly.util.ThreadAttachment;

import com.sun.grizzly.util.ThreadAttachment.Mode;
import java.io.IOException;

import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;

import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;

import java.security.cert.X509Certificate;

import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import org.jvnet.glassfish.comms.util.LogUtil;
import java.util.logging.Logger;

/**
*
* @author ekrigro
*/
public class MessageProcessorFilter implements ProtocolFilter, Callable {

    private final static Logger logger = LogUtil.SIP_LOGGER.getLogger();
    private final Layer _networkHandler;
    /**
     * Should use a attribute from request-processing rather
     * than a system property. default is false.
     */
    private static final boolean finalRequestOnContainerThreadPool =
            Boolean.getBoolean("org.jvnet.glassfish.comms.finalRequestOnContainerThreadPool");
    private int requestTimeOut;
    private boolean isRequestBlocked = false;
   
    /** Bytebuffer pool instead of static GrizzlyReference. */
    private ByteBufferPool _bbPool;
    private AsyncWriteCallbackHandler _asyncWriteCallbackHandler;

    /** Creates a new instance of MessageProcessorFilter */
    public MessageProcessorFilter(Layer layer, int arequestTimeout,
            boolean disablerequests, ByteBufferPool bbPool, AsyncWriteCallbackHandler asyncWriteCallbackHandler) {
        _networkHandler = layer;
        requestTimeOut = arequestTimeout;
        isRequestBlocked = disablerequests;
        _bbPool = bbPool;
        _asyncWriteCallbackHandler = asyncWriteCallbackHandler;
    }

    public MessageProcessorFilter(Layer layer, int arequestTimeout, ByteBufferPool bbPool, AsyncWriteCallbackHandler asyncWriteCallbackHandler) {
        this(layer, arequestTimeout, false, bbPool, asyncWriteCallbackHandler);
    }

    public boolean execute(final Context ctx) throws IOException {
        SipServletMessageImpl parsedMessage = null;
        Socket s = null;
        InetSocketAddress remoteAddress = null;
        SipServletMessageImpl _message = null;
        boolean invokeNextFilter = true;

        final WorkerThread workerThread =
                ((WorkerThread) Thread.currentThread());
        ByteBuffer buffer = workerThread.getByteBuffer();
        SipParser _parser = SipParser.getInstance();
        final Protocol prot = ctx.getProtocol();
        final SelectionKey key = ctx.getSelectionKey();
        final SelectorHandler handler = ctx.getSelectorHandler();
      final ThreadAttachment currentTA = workerThread.getAttachment();

        TargetTuple remote = null;
        InetSocketAddress local = null;
        X509Certificate[] x509Certs = null;

        switch (prot) {
            case TCP:
                s = ((SocketChannel) key.channel()).socket();
                remoteAddress = (InetSocketAddress) s.getRemoteSocketAddress();
                remote = new TargetTuple(SipTransports.TCP_PROT, remoteAddress);
                local = (InetSocketAddress) s.getLocalSocketAddress();

                break;

            case UDP:
                if (!GrizzlyNetworkManager.useDefaultUDPSelectorHandler){
                    buffer = (ByteBuffer) ctx.removeAttribute
                            (GrizzlyNetworkManager.UDP_BUFFER);               
                } else {
                    ctx.setKeyRegistrationState(Context.KeyRegistrationState.NONE);               
                    handler.register(key, SelectionKey.OP_READ);
                }
                DatagramSocket d = ((DatagramChannel) key.channel()).socket();
                remoteAddress =
                        (InetSocketAddress) ctx.getAttribute(ReadFilter.UDP_SOCKETADDRESS);
                remote = new TargetTuple(SipTransports.UDP_PROT, remoteAddress);
                local = (InetSocketAddress) d.getLocalSocketAddress();
                break;

            case TLS:
                s = ((SocketChannel) key.channel()).socket();
                remoteAddress = (InetSocketAddress) s.getRemoteSocketAddress();
                remote = new TargetTuple(SipTransports.TLS_PROT, remoteAddress);
                local = (InetSocketAddress) s.getLocalSocketAddress();
                Object[] certs =
                        (Object[]) ctx.removeAttribute(GrizzlyNetworkManager.SIP_CERTS);

                if ((certs != null) && (certs.length > 0)) {
                    ArrayList<X509Certificate> al =
                            new ArrayList<X509Certificate>();

                    for (int i = 0; i < certs.length; i++) {
                        if (certs[i] instanceof X509Certificate) {
                            al.add((X509Certificate) certs[i]);
                        } else {
                            logger.log(Level.WARNING,
                                    "sip.network.grizzly.wrong.certs",
                                    new Object[]{certs[i].getClass()});
                        }
                    }

                    x509Certs = al.toArray(new X509Certificate[al.size()]);
                }

                break;
        }

        try {
            int initialSize = 0;
            buffer.flip();

            int remaining = buffer.remaining();
            while (((remaining > 0) && (initialSize != remaining)) ||
                    (parsedMessage == null)) {
                initialSize = remaining;
                if (_message == null) {
                    skipNewLines(buffer);
                }
                if (!buffer.hasRemaining()) {
                    return invokeNextFilter;
                }

                parsedMessage = _parser.parseMessage(_message, buffer, local,
                        remote, null);
                remaining = buffer.remaining();

                if ((parsedMessage != null) &&
                        parsedMessage.isMessageComplete() && remaining > 0) {
                    if (isRequestBlocked) {
                        processMessageBlockedState(parsedMessage);
                        continue;
                    }
                    final SipServletMessageImpl msg = parsedMessage;
                    parsedMessage = null;
                    _message = null;
            final InetSocketAddress _remoteAddress = remoteAddress; 
                    msg.setCertificate(x509Certs);
                    SipContainerThreadPool.getInstance().execute(new Callable() {

                        public Object call() throws Exception {
                            if (prot == Protocol.TLS) {
                                if (currentTA != null) {
                                    ((WorkerThread) Thread.currentThread()).
                                            setSSLEngine(currentTA.getSSLEngine());
                                    ((WorkerThread) Thread.currentThread()).
                                            updateAttachment(Mode.SSL_ENGINE);
                                } else {
                                    logger.log(Level.WARNING,
                                            "Thread attachment is null");
                                    return null;
                                }
                            }
                            processMessage(msg, key, handler, _remoteAddress,
                                    prot);
                            return null;
                        }
                    });
                    continue;
                }

                if ((parsedMessage == null) ||
                        !parsedMessage.isMessageComplete()) {
                    // UDP packet are *always* read using a single read, hence
                    // no need to try another read using a temporary Selector.
                    if (prot != Protocol.UDP) {
                        if (logger.isLoggable(Level.FINEST)) {
                            logger.log(Level.FINEST,
                                    "sip.network.grizzly.incomplete.tcp.request",
                                    new Object[]{buffer.position()});
                        }
                        initialSize = remaining;
                        if (buffer.hasRemaining()) {
                            buffer.compact();
                        } else {
                            buffer.clear();
                        }

                        // The thread might block when reading more bytes using
                        // a temporary Selector.
                        ByteBufferInputStream inputStream =
                                new ByteBufferInputStream();
                        inputStream.setSecure((prot == Protocol.TLS));
                        inputStream.setSelectionKey(ctx.getSelectionKey());
                        inputStream.setReadTimeout(requestTimeOut * 1000);
                        int nRead = inputStream.read(buffer);
                        if (nRead <= 0) {
                            logger.log(Level.SEVERE,
                                    "sip.network.grizzly.readtimeout",
                                    new Object[]{requestTimeOut, nRead, buffer});
                            if (logger.isLoggable(Level.FINE)) {
                                SocketChannel channel = (SocketChannel) ctx.getSelectionKey().
                                        channel();
                                logger.log(Level.FINE,
                                        "sip.network.grizzly.readtimeout.channel" +
                                        channel);
                            }
                            if (parsedMessage != null) {
                                logger.log(Level.SEVERE,
                                        "sip.network.grizzly.readtimeout.drop",
                                        new Object[]{parsedMessage.toString()});
                            }                            // Do not invoke the next ProtocolFilter, if any.
                            return false;
                        }
                        remaining = buffer.remaining();
                        _message = parsedMessage;
                    } else {
                        return true;
                    }
                }
            }
            if (parsedMessage != null) {
                if (isRequestBlocked) {
                    processMessageBlockedState(parsedMessage);
                    return false;
                }
                parsedMessage.setCertificate(x509Certs);
                if (prot == Protocol.UDP) {
                    processMessage(parsedMessage, key, handler, remoteAddress,
                            prot);
                } else {
                    if (!finalRequestOnContainerThreadPool) {
                        /**
                         * The key has to be registered back here for TCP, because
                         * the request will be processesd in the same worker thread
                         * and further requests cannot be read until this request
                         * is processed by the app.
                         */                    
                        ctx.setKeyRegistrationState(Context.KeyRegistrationState.NONE);
                        handler.register(key, SelectionKey.OP_READ);
                        processMessage(parsedMessage, key, handler,
                                remoteAddress, prot);
                    } else {
                        /**
                         * This is necessary if we have to ensure (mitigate
                         * ) that the messages are processed in same order.                      * TODO : To register the key, the buffer
                         * has to be copied into another buffer because this buffer
                         * will be reused when this worker thread is used for processing.
                         */
                        final SipServletMessageImpl finalProcessedMessage =
                                parsedMessage;
                        final InetSocketAddress finalRemoteAddress =
                                remoteAddress;
                        SipContainerThreadPool.getInstance().execute(new Callable() {

                            public Object call() throws Exception {
                                if (currentTA != null) {
                                    ((WorkerThread) Thread.currentThread()).
                                            setSSLEngine(currentTA.getSSLEngine());
                                    ((WorkerThread) Thread.currentThread()).
                                            updateAttachment(Mode.SSL_ENGINE);
                                } else {
                                    logger.log(Level.WARNING,
                                            "Thread attachment is null");
                                    return null;
                                }
                                processMessage(finalProcessedMessage,
                                        key, handler, finalRemoteAddress, prot);
                                return null;
                            }
                        });
                    }
                }
            }
        } catch (Throwable t) {
            invokeNextFilter = false;
            if (t instanceof Exception) {
                logger.log(Level.SEVERE,
                        "sip.network.grizzly.request.exception", t);
            } else {
                // FIXME alarm for e.g. OutOfMemoryError
                logger.log(Level.SEVERE, "sip.network.grizzly.request.exception",
                        t);
            }

            if (SipMonitoring.isEnabled(SipMonitoring.NETWORK_MANAGER)) {
                if (((TCPSelectorHandler) handler).getInet() != null) {
                    ((NetworkManager) _networkHandler).incrEasInvalidSipMessages(
                            ((TCPSelectorHandler) handler).getInet().getHostAddress(),
                            ((TCPSelectorHandler) handler).getPort());
                } else {
                     ((NetworkManager) _networkHandler).incrEasInvalidSipMessages(
                             local.getAddress().getHostAddress(), -1);
                }
            }
        } finally {
            buffer.clear();
            if ((prot == Protocol.UDP) &&
                    (!GrizzlyNetworkManager.useDefaultUDPSelectorHandler)){
                _bbPool.releaseBuffer(buffer);
            }
            _message = null;
        }

        return invokeNextFilter;
    }

    public boolean postExecute(Context context) throws IOException {
        return true;
    }

    private void processMessage(final SipServletMessageImpl message,
            SelectionKey key, SelectorHandler handler,
            SocketAddress remoteAdress, Protocol prot) {
        if (message.getMessageType() ==
                SipServletMessageImpl.SipMessageType.SipRequest) {
            SipServletRequestImpl req = (SipServletRequestImpl) message;

            if (logger.isLoggable(Level.FINEST)) {
                logger.log(Level.FINEST,
                        "sip.network.grizzly.in.request",
                        new Object[]{req.getMethod(), req.toString()});
            }

            if (hasBodyWithoutContentType(message)) {
                return;
            }

            req.pushTransactionDispatcher(_networkHandler);
            ResponseDispatcher rd = null;
            if (prot == Protocol.TCP) {
                rd = new StreamResponseDispatcher(handler, key, _bbPool, _asyncWriteCallbackHandler);
            }
            else if (prot == Protocol.TLS) {
                rd = new TLSResponseDispatcher(handler, key, _bbPool, _asyncWriteCallbackHandler);
            }
           
            if (rd != null)
                req.pushTransactionDispatcher(rd); //Could be the same channel

            req.pushApplicationDispatcher(_networkHandler);
            LayerHelper.next(req, _networkHandler, _networkHandler);

            if (SipMonitoring.isEnabled(SipMonitoring.NETWORK_MANAGER)) {
                if (((TCPSelectorHandler)handler).getInet() != null){
                ((NetworkManager) _networkHandler).incrEasReceivedSipRequests(
                        ((TCPSelectorHandler)handler).getInet().getHostAddress(),
                        ((TCPSelectorHandler)handler).getPort());
                } else {
                    ((NetworkManager) _networkHandler).incrEasReceivedSipRequests(
                            message.getLocal().getAddress().getHostAddress(), -1);
                }
                ((NetworkManager) _networkHandler).incrReqInMethodCounter(req.getMethod());
            }


        } else {
            SipServletResponseImpl resp = (SipServletResponseImpl) message;
            Header cseq = resp.getRawHeader(Header.CSEQ);
            /*
             * this should never be null
             */
            if ((cseq == null) || (cseq.getValue() == null)) {
                logger.log(Level.SEVERE, "sip.network.grizzlu.request.cseq.null");
                if (SipMonitoring.isEnabled(SipMonitoring.NETWORK_MANAGER)) {
                    if (((TCPSelectorHandler) handler).getInet() != null){
                    ((NetworkManager) _networkHandler).incrEasInvalidSipMessages(
                            ((TCPSelectorHandler) handler).getInet().getHostAddress(),
                            ((TCPSelectorHandler) handler).getPort());
                    } else {
                        ((NetworkManager) _networkHandler).incrEasReceivedSipRequests(
                            message.getLocal().getAddress().getHostAddress(), -1);
                    }
                }
                return;
            }

            String c = cseq.getValue();
            int index = c.indexOf(' ');
            resp.setMethod(c.substring(index + 1));

            if (logger.isLoggable(Level.FINEST)) {
                logger.log(Level.FINEST, "sip.network.grizzly.in.response",
                        new Object[]{resp.getStatus(), resp.getMethod(),
                    resp.toString()
                });
            }

            //_networkHandler.next(resp);
            LayerHelper.next(resp, _networkHandler, _networkHandler);


            if (SipMonitoring.isEnabled(SipMonitoring.NETWORK_MANAGER)) {
                if (((TCPSelectorHandler)handler).getInet() != null){
                ((NetworkManager) _networkHandler).incrEasReceivedSipResponses(((TCPSelectorHandler)handler).getInet().getHostAddress(),
                        ((TCPSelectorHandler)handler).getPort());
                } else {
                    ((NetworkManager) _networkHandler).incrEasReceivedSipResponses(
                    message.getLocal().getAddress().getHostAddress(), -1);
                }
                ((NetworkManager) _networkHandler).incrRespInStatCodeCounter(resp.getStatus());
            }

        }
    }

    public boolean hasBodyWithoutContentType(SipServletMessageImpl message) {
        // The SIP-stack should refuse all request with body and without
        // Content-Type header field.
        if (message.hasBody() && (message.getContentType() == null)) {
            try {
                if (logger.isLoggable(Level.FINEST)) {
                    logger.log(Level.FINEST,
                            "sip.network.grizzly.missing.content.type");
                }

                SipServletRequestImpl req = (SipServletRequestImpl) message;
                String phraze = "Missing Content-Type header field";
                SipServletResponseImpl resp = req.createTerminatingResponse(400,
                        phraze);

                sendErrorResponse(resp);
            } catch (Exception ignore) {
                if (logger.isLoggable(Level.FINEST)) {
                    logger.log(Level.FINEST, "unexpected exception: ", ignore);
                }
            }

            return true;
        }

        return false;
    }

    // TODO
    public Object call() throws Exception {
        return null;
    }

    private void skipNewLines(ByteBuffer buffer) {
        int position = buffer.position();
        while (buffer.remaining() == 2) {
            if (buffer.get(position) == '\r' && buffer.get(position + 1) == '\n') {
                position += 2;
                buffer.position(position);
            } else {
                break;
            }
        }
    }

    private void processMessageBlockedState(SipServletMessageImpl parsedmessage) {
        if ((parsedmessage.getMessageType() ==
                SipServletMessageImpl.SipMessageType.SipRequest) && (!parsedmessage.getMethod().
                equals("ACK"))) {
            if (logger.isLoggable(Level.FINE)) {
                logger.log(Level.FINE, "sip.network.grizzly.reject.request",
                        new Object[]{parsedmessage});
            }
            /**
             * Add some monitoring info here.
             */
            SipServletRequestImpl req =
                    (SipServletRequestImpl) parsedmessage;

            SipServletResponseImpl resp = req.createTerminatingResponse(500);
            sendErrorResponse(resp);
        }
    }

    private void sendErrorResponse(SipServletResponseImpl resp) {

        while (resp.popDispatcher() != null) {
        }

        TargetResolver tr = TargetResolver.getInstance();
        TargetTuple tt = null;
        try {
            tt = tr.resolveResponse(resp);
        } catch (Exception e) {
            if (logger.isLoggable(Level.FINEST)) {
                logger.log(Level.FINEST,
                        "sip.network.grizzly.failed.resolution");
            }
        }
        if (tt != null) {
            resp.setRemote(tt);
            _networkHandler.dispatch(resp);
        } else if (logger.isLoggable(Level.FINEST)) {
            logger.log(Level.FINEST,
                    "sip.network.grizzly.failed.resolution");
        }
    }
}
TOP

Related Classes of com.ericsson.ssa.container.MessageProcessorFilter

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.