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

org.jdiameter.server.impl.io.tcp.NetworkGuard Maven / Gradle / Ivy

There is a newer version: 2.0.5
Show newest version
/*
 * TeleStax, Open Source Cloud Communications
 * Copyright 2011-2014, TeleStax Inc. and individual contributors
 * by the @authors tag.
 *
 * This program is free software: you can redistribute it and/or modify
 * under the terms of the GNU Affero 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see 
 *
 * This file incorporates work covered by the following copyright and
 * permission notice:
 *
 *   JBoss, Home of Professional Open Source
 *   Copyright 2007-2011, Red Hat, Inc. and individual contributors
 *   by the @authors tag. See the copyright.txt in the distribution for a
 *   full listing of individual contributors.
 *
 *   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.jdiameter.server.impl.io.tcp;

import static org.jdiameter.server.impl.helpers.Parameters.BindDelay;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.jdiameter.client.api.parser.IMessageParser;
import org.jdiameter.client.impl.transport.tcp.TCPClientConnection;
import org.jdiameter.common.api.concurrent.DummyConcurrentFactory;
import org.jdiameter.common.api.concurrent.IConcurrentFactory;
import org.jdiameter.server.api.IMetaData;
import org.jdiameter.server.api.io.INetworkConnectionListener;
import org.jdiameter.server.api.io.INetworkGuard;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * TCP implementation of {@link org.jdiameter.server.api.io.INetworkGuard}.
 *
 * @author  Alexandre Mendonca 
 * @author  Bartosz Baranowski 
 */
@SuppressWarnings("all") //3rd party lib
public class NetworkGuard implements INetworkGuard {

    private static final Logger logger = LoggerFactory.getLogger(NetworkGuard.class);

    protected IMessageParser parser;
    protected IConcurrentFactory concurrentFactory;
    protected int port;
    protected long bindDelay;
    protected CopyOnWriteArrayList listeners = new CopyOnWriteArrayList();
    protected boolean isWork = false;
    //  protected Selector selector;
    //  protected ServerSocket serverSocket;

    //private Thread thread;
    private List tasks = new ArrayList();

    @Deprecated
    public NetworkGuard(InetAddress inetAddress, int port, IMessageParser parser) throws Exception {
        this(inetAddress, port, null, parser, null);
    }

    public NetworkGuard(InetAddress inetAddress, int port,
            IConcurrentFactory concurrentFactory, IMessageParser parser,
            IMetaData data) throws Exception {
        this(new InetAddress[] { inetAddress }, port, concurrentFactory, parser, data);
    }

    public NetworkGuard(InetAddress[] inetAddress, int port,
            IConcurrentFactory concurrentFactory, IMessageParser parser,
            IMetaData data) throws Exception {
        this.port = port;
        this.parser = parser;
        this.concurrentFactory = concurrentFactory == null ? new DummyConcurrentFactory() : concurrentFactory;
        //this.thread = this.concurrentFactory.getThread("NetworkGuard", this);
        this.bindDelay = data.getConfiguration().getLongValue(BindDelay.ordinal(), (Long) BindDelay.defValue());

        try {
            for (int addrIdx = 0; addrIdx < inetAddress.length; addrIdx++) {
                GuardTask guardTask = new GuardTask(new InetSocketAddress(inetAddress[addrIdx], port));
                this.concurrentFactory.getThreadPool().execute(guardTask);
                tasks.add(guardTask);
            }
            isWork = true;
        } catch (Exception exc) {
            destroy();
            throw new Exception(exc);
        }
    }

    @Override
    public void addListener(INetworkConnectionListener listener) {
        if (!listeners.contains(listener)) {
            listeners.add(listener);
        }
    }

    @Override
    public void remListener(INetworkConnectionListener listener) {
        listeners.remove(listener);
    }

    @Override
    public String toString() {
        return "NetworkGuard:" + (this.tasks.size() != 0 ? this.tasks : "closed");
    }

    @Override
    public void destroy() {
        isWork = false;
        Iterator it = this.tasks.iterator();
        while (it.hasNext()) {
            GuardTask gt = it.next();
            it.remove();
            gt.cleanTask();
        }
    }

    private class GuardTask implements Runnable {
        private Thread thread;
        private Selector selector;
        private ServerSocket serverSocket;

        private final ScheduledExecutorService binder = Executors.newSingleThreadScheduledExecutor();

        GuardTask(final InetSocketAddress addr) throws IOException {
            if (bindDelay > 0) {
                logger.info("Socket binding will be delayed by {}ms...", bindDelay);
            }

            Runnable task = new Runnable() {
                @Override
                public void run() {
                    try {
                        logger.debug("Binding {} after delaying {}ms...", addr, bindDelay);
                        final ServerSocketChannel ssc = ServerSocketChannel.open();
                        ssc.configureBlocking(false);
                        serverSocket = ssc.socket();
                        serverSocket.bind(addr);

                        selector = Selector.open();
                        ssc.register(selector, SelectionKey.OP_ACCEPT, addr);
                        logger.info("Open server socket {} ", serverSocket);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            };
            binder.schedule(task, bindDelay, TimeUnit.MILLISECONDS);
        }

        public void start() {
            this.thread.start();
        }

        @Override
        public void run() {
            try {
                while (isWork) {
                    if (selector == null) {
                        logger.trace("Selector is still null, stack is waiting for binding...");
                        Thread.sleep(250);
                        continue;
                    }
                    // without timeout when we kill socket, this causes errors, bug in VM ?
                    int num = selector.select(100);
                    if (num == 0) {
                        continue;
                    }
                    Set keys = selector.selectedKeys();
                    try {
                        for (SelectionKey key : keys) {
                            if ((key.readyOps() & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT) {
                                try {
                                    Socket s = serverSocket.accept();
                                    logger.info("Open incomming connection {}", s);
                                    TCPClientConnection client = new TCPClientConnection(null, concurrentFactory, s, parser,
                                            null);
                                    // PCB added logging
                                    logger.debug("Finished initialising TCPClientConnection for {}", s);
                                    for (INetworkConnectionListener listener : listeners) {
                                        listener.newNetworkConnection(client);
                                    }
                                } catch (Exception e) {
                                    logger.warn("Can not create incoming connection", e);
                                }
                            }
                        }
                    } catch (Exception e) {
                        logger.debug("Failed to accept connection,", e);
                    } finally {
                        keys.clear();
                    }
                }
            } catch (Exception exc) {
                logger.warn("Server socket stopped", exc);
            }
        }

        public void cleanTask() {
            try {
                if (thread != null) {
                    thread.join(2000);
                    if (thread.isAlive()) {
                        // FIXME: remove ASAP
                        thread.interrupt();
                    }
                    thread = null;
                }
            } catch (InterruptedException e) {
                logger.debug("Can not stop thread", e);
            }
            if (selector != null) {
                try {
                    selector.close();
                } catch (Exception e) {
                    // ignore
                }
                selector = null;
            }
            if (serverSocket != null) {
                try {
                    serverSocket.close();
                } catch (Exception e) {
                    // ignore
                }
                serverSocket = null;
            }
        }

        @Override
        public String toString() {
            return "GuardTask [serverSocket=" + serverSocket + "]";
        }

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy