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

org.xsocket.connection.spi.Acceptor Maven / Gradle / Ivy

There is a newer version: 2.8.15
Show newest version
/*
 *  Copyright (c) xsocket.org, 2006 - 2008. All rights reserved.
 *
 *  This library 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 library 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 library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Please refer to the LGPL license at: http://www.gnu.org/copyleft/lesser.txt
 * The latest copy of this software may be found on http://www.xsocket.org/
 */
package org.xsocket.connection.spi;


import java.io.IOException;
import java.net.BindException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.net.ssl.SSLContext;

import org.xsocket.IDispatcher;



/**
 * The acceptor ist responsible to accept new incoming connections, and
 * register these on the dispatcher.

* * @author [email protected] */ final class Acceptor implements IAcceptor { private static final Logger LOG = Logger.getLogger(Acceptor.class.getName()); @SuppressWarnings("unchecked") private static final Map SUPPORTED_OPTIONS = new HashMap(); static { SUPPORTED_OPTIONS.put(SO_RCVBUF, Integer.class); SUPPORTED_OPTIONS.put(SO_REUSEADDR, Boolean.class); } // io handler private static final DefaultIoProvider IO_PROVIDER = new DefaultIoProvider(); private IAcceptorCallback callback = null; // running flag private volatile boolean isRunning = true; // Socket private ServerSocketChannel serverChannel = null; // SSL private boolean sslOn = false; private SSLContext sslContext = null; // memory management private int preallocationSize = DefaultIoProvider.DEFAULT_READ_BUFFER_PREALLOCATION_SIZE; private int bufferMinsize = DefaultIoProvider.DEFAULT_READ_BUFFER_MIN_SIZE; private boolean preallocation = true; private boolean useDirect = false; // dispatcher management private final LinkedList dispatchers = new LinkedList(); private int size = 0; private int pointer = 0; // listeners private final ArrayList listeners = new ArrayList(); // statistics private long acceptedConnections = 0; private long lastRequestAccpetedRate = System.currentTimeMillis(); public Acceptor(IAcceptorCallback callback, InetSocketAddress address, int backlog) throws IOException { this(callback, address, backlog, null, false); } public Acceptor(IAcceptorCallback callback, InetSocketAddress address, int backlog, SSLContext sslContext, boolean sslOn) throws IOException { this.callback = callback; this.sslContext = sslContext; this.sslOn = sslOn; LOG.fine("try to bind server on " + address); // create a new server socket serverChannel = ServerSocketChannel.open(); serverChannel.configureBlocking(true); serverChannel.socket().setSoTimeout(0); // accept method never times out serverChannel.socket().setReuseAddress(true); // set reuse address by default (can be override by socketConfig) try { setDispatcherSize(Runtime.getRuntime().availableProcessors() + 1); assert (serverChannel != null); serverChannel.socket().bind(address, backlog); } catch (BindException be) { if (serverChannel != null) { serverChannel.close(); } LOG.info("error occured while binding server on on " + address + ". Reason: " + be.toString()); throw be; } } void addListener(IAcceptorListener listener) { listeners.add(listener); } boolean removeListener(IAcceptorListener listener) { return listeners.remove(listener); } void setOption(String name, Object value) throws IOException { if (name.equals(IAcceptor.SO_RCVBUF)) { serverChannel.socket().setReceiveBufferSize((Integer) value); } else if (name.equals(IAcceptor.SO_REUSEADDR)) { serverChannel.socket().setReuseAddress((Boolean) value); } else { LOG.warning("option " + name + " is not supproted for " + this.getClass().getName()); } } /** * {@inheritDoc} */ public Object getOption(String name) throws IOException { if (name.equals(IAcceptor.SO_RCVBUF)) { return serverChannel.socket().getReceiveBufferSize(); } else if (name.equals(IAcceptor.SO_REUSEADDR)) { return serverChannel.socket().getReuseAddress(); } else { LOG.warning("option " + name + " is not supproted for " + this.getClass().getName()); return null; } } @SuppressWarnings("unchecked") public Map getOptions() { return Collections.unmodifiableMap(SUPPORTED_OPTIONS); } /** * {@inheritDoc} */ public InetAddress getLocalAddress() { return serverChannel.socket().getInetAddress(); } /** * {@inheritDoc} */ public int getLocalPort() { return serverChannel.socket().getLocalPort(); } /** * {@inheritDoc} */ public void listen() throws IOException { callback.onConnected(); accept(); } private void accept() { // acceptor loop while (isRunning) { try { // blocking accept call SocketChannel channel = serverChannel.accept(); // create IoSocketHandler IoSocketDispatcher dispatcher = nextDispatcher(); IIoHandler ioHandler = IO_PROVIDER.createIoHandler(false, dispatcher, channel, sslContext, sslOn); // notify call back callback.onConnectionAccepted(ioHandler); acceptedConnections++; } catch (Exception e) { if (LOG.isLoggable(Level.FINE)) { // if acceptor is running (.close() causes that any // thread currently blocked in accept() will throw a SocketException) if (serverChannel.isOpen()) { LOG.fine("error occured while accepting connection: " + e.toString()); } } } } // acceptor loop } private IoSocketDispatcher nextDispatcher() { IoSocketDispatcher result = null; try { // round-robin approach pointer++; if (pointer >= size) { pointer = 0; } result = dispatchers.get(pointer); } catch (Exception concurrentException) { if (isRunning) { result = nextDispatcher(); } } return result; } @SuppressWarnings("unchecked") private void updateDispatcher() { if (isRunning) { synchronized (dispatchers) { int currentRunning = dispatchers.size(); if (currentRunning != size) { if (currentRunning > size) { for (int i = size; i < currentRunning; i++) { IDispatcher dispatcher = dispatchers.getLast(); dispatchers.remove(dispatcher); try { dispatcher.close(); } catch (IOException ioe) { if (LOG.isLoggable(Level.FINE)) { LOG.fine("error occured by closing the dispatcher " + dispatcher + ". reason " + ioe.toString()); } } for (IAcceptorListener listener : listeners) { listener.onDispatcherRemoved(dispatcher); } } } else if ( currentRunning < size) { for (int i = currentRunning; i < size; i++) { UnsynchronizedMemoryManager memoryManager = null; if (preallocation) { memoryManager = UnsynchronizedMemoryManager.createPreallocatedMemoryManager(preallocationSize, bufferMinsize, useDirect); } else { memoryManager = UnsynchronizedMemoryManager.createNonPreallocatedMemoryManager(useDirect); } IoSocketDispatcher dispatcher = new IoSocketDispatcher(memoryManager); dispatchers.addLast(dispatcher); Thread t = new Thread(dispatcher); t.setDaemon(false); t.setName(IoSocketDispatcher.DISPATCHER_PREFIX + "#" + i); t.start(); for (IAcceptorListener listener : listeners) { listener.onDispatcherAdded(dispatcher); } } } } IDispatcher[] connectionDispatchers = new IDispatcher[dispatchers.size()]; for (int i = 0; i < connectionDispatchers.length; i++) { connectionDispatchers[i] = dispatchers.get(i); } } } } /** * {@inheritDoc} */ public void close() throws IOException { if (isRunning) { isRunning = false; if (LOG.isLoggable(Level.FINE)) { LOG.fine("closing acceptor"); } try { // closes the server socket serverChannel.close(); } catch (Exception ignore) { } shutdownDispatcher(); callback.onDisconnected(); } } /** * shutdown the pool * */ private void shutdownDispatcher() { if (LOG.isLoggable(Level.FINER)) { LOG.fine("terminate dispatchers"); } synchronized (dispatchers) { for (IDispatcher dispatcher : dispatchers) { try { dispatcher.close(); for (IAcceptorListener listener : listeners) { listener.onDispatcherRemoved(dispatcher); } } catch (IOException ioe) { if (LOG.isLoggable(Level.FINE)) { LOG.fine("error occured by closing the dispatcher " + dispatcher + ". reason " + ioe.toString()); } } } } dispatchers.clear(); } public int getNumberOfOpenConnections() { return getOpenConntionInfos().size(); } public List getOpenConntionInfos() { List result = new ArrayList(); for (IDispatcher dispatcher : getDispatchers()) { for (IoSocketHandler handler : dispatcher.getRegistered()) { result.add(handler.toString()); } } return result; } @SuppressWarnings("unchecked") List> getDispatchers() { List> result = null; synchronized (dispatchers) { result = (List>) dispatchers.clone(); } return result; } void setDispatcherSize(int size) { this.size = size; updateDispatcher(); } int getDispatcherSize() { return size; } boolean getReceiveBufferIsDirect() { return useDirect; } void setReceiveBufferIsDirect(boolean isDirect) { this.useDirect = isDirect; for (IoSocketDispatcher dispatcher: dispatchers) { dispatcher.setReceiveBufferIsDirect(isDirect); } } boolean isReceiveBufferPreallocationMode() { return preallocation; } void setReceiveBufferPreallocationMode(boolean mode) { this.preallocation = mode; synchronized (dispatchers) { for (IoSocketDispatcher dispatcher: dispatchers) { dispatcher.setReceiveBufferPreallocationMode(mode); } } } void setReceiveBufferPreallocatedMinSize(Integer minSize) { this.bufferMinsize = minSize; synchronized (dispatchers) { for (IoSocketDispatcher dispatcher: dispatchers) { dispatcher.setReceiveBufferPreallocatedMinSize(minSize); } } } Integer getReceiveBufferPreallocatedMinSize() { return bufferMinsize; } /** * get the size of the preallocation buffer, * for reading incoming data * * @return preallocation buffer size */ Integer getReceiveBufferPreallocationSize() { return preallocationSize; } /** * set the size of the preallocation buffer, * for reading incoming data * * @param size the preallocation buffer size */ void setReceiveBufferPreallocationSize(int size) { preallocationSize = size; for (IoSocketDispatcher dispatcher: dispatchers) { dispatcher.setReceiveBufferPreallocatedSize(size); } } double getAcceptedRateCountPerSec() { double rate = 0; long elapsed = System.currentTimeMillis() - lastRequestAccpetedRate; if (acceptedConnections == 0) { rate = 0; } else if (elapsed == 0) { rate = Integer.MAX_VALUE; } else { rate = (((double) (acceptedConnections * 1000)) / elapsed); } lastRequestAccpetedRate = System.currentTimeMillis(); acceptedConnections = 0; return rate; } long getSendRateBytesPerSec() { long rate = 0; for (IoSocketDispatcher dispatcher : dispatchers) { rate += dispatcher.getSendRateBytesPerSec(); } return rate; } long getReceiveRateBytesPerSec() { long rate = 0; for (IoSocketDispatcher dispatcher : dispatchers) { rate += dispatcher.getReceiveRateBytesPerSec(); } return rate; } @SuppressWarnings("unchecked") long getNumberOfConnectionTimeouts() { long timeouts = 0; LinkedList copy = null; synchronized (dispatchers) { copy = (LinkedList) dispatchers.clone(); } for (IoSocketDispatcher dispatcher : copy) { timeouts += dispatcher.getCountConnectionTimeout(); } return timeouts; } @SuppressWarnings("unchecked") public long getNumberOfIdleTimeouts() { long timeouts = 0; LinkedList copy = null; synchronized (dispatchers) { copy = (LinkedList) dispatchers.clone(); } for (IoSocketDispatcher dispatcher : copy) { timeouts += dispatcher.getCountIdleTimeout(); } return timeouts; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy