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

org.xsocket.connection.IoProvider Maven / Gradle / Ivy

/*
 * Copyright (c) xlightweb.org, 2006 - 2010. 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;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.Map;
import java.util.Random;
import java.util.Timer;
import java.util.UUID;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.net.ssl.SSLContext;

import org.xsocket.DataConverter;




/**
 * IoProvider
 * 
 * 
 * @author [email protected]
 */
final class IoProvider  {

	private static final Logger LOG = Logger.getLogger(IoProvider.class.getName());

	static final String SO_SNDBUF = IConnection.SO_SNDBUF;
	static final String SO_RCVBUF = IConnection.SO_RCVBUF;
	static final String SO_REUSEADDR = IConnection.SO_REUSEADDR;
	static final String SO_TIMEOUT = "SOL_SOCKET.SO_TIMEOUT";
	static final String SO_KEEPALIVE = IConnection.SO_KEEPALIVE;
	static final String SO_LINGER = IConnection.SO_LINGER;
	static final String TCP_NODELAY = IConnection.TCP_NODELAY;

	
	static final int UNLIMITED = INonBlockingConnection.UNLIMITED;
	static final long DEFAULT_CONNECTION_TIMEOUT_MILLIS = IConnection.DEFAULT_CONNECTION_TIMEOUT_MILLIS;
	static final long DEFAULT_IDLE_TIMEOUT_MILLIS = IConnection.DEFAULT_IDLE_TIMEOUT_MILLIS;

	
	private static final Timer TIMER = new Timer("xIoTimer", true);
	private static IoSocketDispatcherPool globalClientDispatcherPool;

	
	
	// transfer props
    static final String TRANSFER_MAPPED_BYTE_BUFFER_MAX_MAP_SIZE_KEY = "org.xsocket.connection.transfer.mappedbytebuffer.maxsize";
    static final int DEFAULT_TRANSFER_BYTE_BUFFER_MAX_MAP_SIZE = 16384;
    private static Integer transferByteBufferMaxSize;

		
	// connection props
	public static final String SUPPRESS_SYNC_FLUSH_WARNING_KEY = "org.xsocket.connection.suppressSyncFlushWarning";
	public static final String DEFAULT_SUPPRESS_SYNC_FLUSH_WARNING = "false";
    public static final String SUPPRESS_REUSE_BUFFER_WARNING_KEY = "org.xsocket.connection.suppressReuseBufferWarning";
    public static final String DEFAULT_SUPPRESS_REUSE_BUFFER_WARNING = "false";
    public static final String SUPPRESS_SYNC_FLUSH_COMPLETION_HANDLER_WARNING_KEY = "org.xsocket.connection.suppressSyncFlushCompletionHandlerWarning";
    public static final String DEFAULT_SUPPRESS_SYNC_FLUSH_COMPLETION_HANDLER_WARNING = "false";

    
    private static boolean IS_REUSE_ADDRESS = Boolean.parseBoolean(System.getProperty("org.xsocket.connection.server.reuseaddress", "true"));
    
	
	// dispatcher props
	public static final String COUNT_DISPATCHER_KEY = "org.xsocket.connection.dispatcher.initialCount";
	private static final String COUNT_SERVER_DISPATCHER_KEY = "org.xsocket.connection.server.dispatcher.initialCount";
	private static final String COUNT_CLIENT_DISPATCHER_KEY = "org.xsocket.connection.client.dispatcher.initialCount";
	private static final String MAX_HANDLES = "org.xsocket.connection.dispatcher.maxHandles";	
	private static final String DETACH_HANDLE_ON_NO_OPS = "org.xsocket.connection.dispatcher.detachHandleOnNoOps";
	private static final String DEFAULT_DETACH_HANDLE_ON_NO_OPS = "false";
	private static final String IS_BYPASSING_WRITE_ALLOWED = "org.xsocket.connection.dispatcher.bypassingWriteAllowed";
	private static final String DEFAULT_IS_BYPASSING_WRITE_ALLOWED = "true";
	
	
	   
    ////////////////////////////////////////////////
    // use direct buffer or non-direct buffer?
    //
    // current vm implementations (Juli/2007) seems to have
    // problems by gc direct buffers.
    //
    // links
    // * [Java bugdatabase] http://bugs.sun.com/bugdatabase/view_bug.do;jsessionid=94d5403110224b692e5354bd87a92:WuuT?bug_id=6210541
    // * [forum thread]     http://forums.java.net/jive/thread.jspa?messageID=223706&tstart=0
    // * [mina]             https://issues.apache.org/jira/browse/DIRMINA-391
    //
    ////////////////////////////////////////////////

	
	// direct buffer?
	public static final String DEFAULT_USE_DIRECT_BUFFER = "false";
	public static final String CLIENT_READBUFFER_USE_DIRECT_KEY             = "org.xsocket.connection.client.readbuffer.usedirect";
	public static final String SERVER_READBUFFER_USE_DIRECT_KEY             = "org.xsocket.connection.server.readbuffer.usedirect";
	private static final String WRITE_BUFFER_USE_DIRECT_KEY                 = "org.xsocket.connection.writebuffer.usedirect";
	
	
	// preallocation params
	public static final String DEFAULT_READ_BUFFER_PREALLOCATION_ON = "true";
	public static final int DEFAULT_READ_BUFFER_PREALLOCATION_SIZE = 16384;
	public static final int DEFAULT_READ_BUFFER_MIN_SIZE = 64;
	
	
	public static final String CLIENT_READBUFFER_PREALLOCATION_ON_KEY       = "org.xsocket.connection.client.readbuffer.preallocation.on";
	public static final String CLIENT_READBUFFER_PREALLOCATION_SIZE_KEY     = "org.xsocket.connection.client.readbuffer.preallocation.size";
	public static final String CLIENT_READBUFFER_PREALLOCATION_MIN_SIZE_KEY = "org.xsocket.connection.client.readbuffer.preallocated.minSize";
	
	public static final String SERVER_READBUFFER_PREALLOCATION_ON_KEY       = "org.xsocket.connection.server.readbuffer.preallocation.on";
	public static final String SERVER_READBUFFER_PREALLOCATION_SIZE_KEY     = "org.xsocket.connection.server.readbuffer.preallocation.size";
	public static final String SERVER_READBUFFER_PREALLOCATION_MIN_SIZE_KEY = "org.xsocket.connection.server.readbuffer.preallocated.minSize";
	
	
	public static final String DEFAULT_CLIENT_MAX_READBUFFER_SIZE_KEY       = "org.xsocket.connection.client.readbuffer.defaultMaxReadBufferThreshold";
	public static final String DEFAULT_SERVER_MAX_READBUFFER_SIZE_KEY       = "org.xsocket.connection.server.readbuffer.defaultMaxReadBufferThreshold";

	public static final String DEFAULT_CLIENT_MAX_WRITEBUFFER_SIZE_KEY       = "org.xsocket.connection.client.readbuffer.defaultMaxWriteBufferThreshold";
	public static final String DEFAULT_SERVER_MAX_WRITEBUFFER_SIZE_KEY       = "org.xsocket.connection.server.readbuffer.defaultMaxWriteBufferThreshold";

	
	private static Integer defaultClientMaxReadbufferSize;
	private static Integer defaultServerMaxReadbufferSize;
	private static Integer defaultClientMaxWritebufferSize;
	private static Integer defaultServerMaxWritebufferSize;

	
	private static final String SSLENGINE_CLIENT_ENABLED_CIPHER_SUITES_KEY  = "org.xsocket.connection.client.ssl.sslengine.enabledCipherSuites";
	private static final String SSLENGINE_SERVER_ENABLED_CIPHER_SUITES_KEY  = "org.xsocket.connection.server.ssl.sslengine.enabledCipherSuites";
	private static final String SSLENGINE_CLIENT_ENABLED_PROTOCOLS_KEY  = "org.xsocket.connection.client.ssl.sslengine.enabledProtocols";
	private static final String SSLENGINE_SERVER_ENABLED_PROTOCOLS_KEY  = "org.xsocket.connection.server.ssl.sslengine.enabledProtocols";
	private static final String SSLENGINE_SERVER_WANT_CLIENT_AUTH_KEY  = "org.xsocket.connection.server.ssl.sslengine.wantClientAuth";
	private static final String SSLENGINE_SERVER_NEED_CLIENT_AUTH_KEY  = "org.xsocket.connection.server.ssl.sslengine.needClientAuth";
	
	
	private static String[] sSLEngineClientEnabledCipherSuites;
	private static String[] sSLEngineServerEnabledCipherSuites;
	private static String[] sSLEngineClientEnabledProtocols;
	private static String[] sSLEngineServerEnabledProtocols;
	private static Boolean sSLEngineWantClientAuth;
	private static Boolean sSLEngineNeedClientAuth; 
	
	
	private static Integer countDispatcher;
	private static Integer countClientDispatcher;
	private static Integer countServerDispatcher;
	private static Integer maxHandles;
	private static boolean detachHandleOnNoOps = true; 
	private static boolean bypassingWriteAllowed = false;
    
    private static Boolean suppressSyncFlushWarning;
    private static boolean suppressSyncFlushCompletionHandlerWarning;

    private static Boolean suppressReuseBufferWarning;
    
	private static Boolean clientReadBufferUseDirect;
	private static Boolean serverReadBufferUseDirect;
	private static Boolean writeBufferUseDirect;
	
	private static Boolean clientReadBufferPreallocationOn;
	private static int clientReadBufferPreallocationsize = DEFAULT_READ_BUFFER_PREALLOCATION_SIZE;
	private static int clientReadBufferMinsize = DEFAULT_READ_BUFFER_MIN_SIZE;
	
	private static Boolean serverReadBufferPreallocationOn;
	private static int serverReadBufferPreallocationsize = DEFAULT_READ_BUFFER_PREALLOCATION_SIZE;
	private static int serverReadBufferMinsize = DEFAULT_READ_BUFFER_MIN_SIZE;

	private final static String idPrefix;


    static {
    	countDispatcher = readIntProperty(COUNT_DISPATCHER_KEY);
    	countClientDispatcher = readIntProperty(COUNT_CLIENT_DISPATCHER_KEY);
    	countServerDispatcher = readIntProperty(COUNT_SERVER_DISPATCHER_KEY);
    	maxHandles = readIntProperty(MAX_HANDLES);
    	
    	detachHandleOnNoOps = readBooleanProperty(DETACH_HANDLE_ON_NO_OPS, DEFAULT_DETACH_HANDLE_ON_NO_OPS);
    	bypassingWriteAllowed = readBooleanProperty(IS_BYPASSING_WRITE_ALLOWED, DEFAULT_IS_BYPASSING_WRITE_ALLOWED);
    	
    	
    	// transfer props
    	transferByteBufferMaxSize = readIntProperty(TRANSFER_MAPPED_BYTE_BUFFER_MAX_MAP_SIZE_KEY, DEFAULT_TRANSFER_BYTE_BUFFER_MAX_MAP_SIZE);

    	
    	// coonection
    	suppressSyncFlushWarning = readBooleanProperty(IoProvider.SUPPRESS_SYNC_FLUSH_WARNING_KEY, DEFAULT_SUPPRESS_SYNC_FLUSH_WARNING);
        suppressSyncFlushCompletionHandlerWarning = readBooleanProperty(IoProvider.SUPPRESS_SYNC_FLUSH_COMPLETION_HANDLER_WARNING_KEY, DEFAULT_SUPPRESS_SYNC_FLUSH_COMPLETION_HANDLER_WARNING);
    	suppressReuseBufferWarning = readBooleanProperty(IoProvider.SUPPRESS_REUSE_BUFFER_WARNING_KEY, DEFAULT_SUPPRESS_REUSE_BUFFER_WARNING);    	
    	
    	// direct buffer?
   		clientReadBufferUseDirect = readBooleanProperty(IoProvider.CLIENT_READBUFFER_USE_DIRECT_KEY, DEFAULT_USE_DIRECT_BUFFER);
   		serverReadBufferUseDirect = readBooleanProperty(IoProvider.SERVER_READBUFFER_USE_DIRECT_KEY, DEFAULT_USE_DIRECT_BUFFER);
   		writeBufferUseDirect = readBooleanProperty(IoProvider.WRITE_BUFFER_USE_DIRECT_KEY, DEFAULT_USE_DIRECT_BUFFER);
   		
   		// thresholds
   		defaultClientMaxReadbufferSize = readIntProperty(IoProvider.DEFAULT_CLIENT_MAX_READBUFFER_SIZE_KEY);
   		defaultServerMaxReadbufferSize = readIntProperty(IoProvider.DEFAULT_SERVER_MAX_READBUFFER_SIZE_KEY);
   		defaultClientMaxWritebufferSize = readIntProperty(IoProvider.DEFAULT_CLIENT_MAX_WRITEBUFFER_SIZE_KEY);
   		defaultServerMaxWritebufferSize = readIntProperty(IoProvider.DEFAULT_SERVER_MAX_WRITEBUFFER_SIZE_KEY);
    	
   		
   		// ssl props 
   		sSLEngineServerEnabledProtocols = readStringArrayProperty(IoProvider.SSLENGINE_SERVER_ENABLED_PROTOCOLS_KEY, null);
   		sSLEngineClientEnabledProtocols = readStringArrayProperty(IoProvider.SSLENGINE_CLIENT_ENABLED_PROTOCOLS_KEY, null);
   		sSLEngineServerEnabledCipherSuites = readStringArrayProperty(IoProvider.SSLENGINE_SERVER_ENABLED_CIPHER_SUITES_KEY, null);
   		sSLEngineClientEnabledCipherSuites = readStringArrayProperty(IoProvider.SSLENGINE_CLIENT_ENABLED_CIPHER_SUITES_KEY, null);
   		sSLEngineWantClientAuth = readBooleanProperty(IoProvider.SSLENGINE_SERVER_WANT_CLIENT_AUTH_KEY, null);
   		sSLEngineNeedClientAuth = readBooleanProperty(IoProvider.SSLENGINE_SERVER_NEED_CLIENT_AUTH_KEY, null);
    	
   		// preallocation
   		clientReadBufferPreallocationOn = readBooleanProperty(IoProvider.CLIENT_READBUFFER_PREALLOCATION_ON_KEY, DEFAULT_READ_BUFFER_PREALLOCATION_ON);
    	if (clientReadBufferPreallocationOn) {
	    	clientReadBufferPreallocationsize = readIntProperty(IoProvider.CLIENT_READBUFFER_PREALLOCATION_SIZE_KEY, DEFAULT_READ_BUFFER_PREALLOCATION_SIZE);
	    	clientReadBufferMinsize = readIntProperty(IoProvider.CLIENT_READBUFFER_PREALLOCATION_MIN_SIZE_KEY, DEFAULT_READ_BUFFER_MIN_SIZE);
    	}

    	
    	serverReadBufferPreallocationOn = readBooleanProperty(IoProvider.SERVER_READBUFFER_PREALLOCATION_ON_KEY, DEFAULT_READ_BUFFER_PREALLOCATION_ON);
    	if (serverReadBufferPreallocationOn) {   		
    		serverReadBufferPreallocationsize = readIntProperty(IoProvider.SERVER_READBUFFER_PREALLOCATION_SIZE_KEY, DEFAULT_READ_BUFFER_PREALLOCATION_SIZE);
    		serverReadBufferMinsize = readIntProperty(IoProvider.SERVER_READBUFFER_PREALLOCATION_MIN_SIZE_KEY, DEFAULT_READ_BUFFER_MIN_SIZE);
    	}


    	// prepare id prefix
    	String base = null;
    	try {
    		base = InetAddress.getLocalHost().getHostAddress();
    	} catch (Exception e) {
    		base = UUID.randomUUID().toString();
    	}

   		int random = 0;
   		Random rand = new Random();
   		do {
   			random = rand.nextInt();
   		} while (random < 0);
   		
   		// ipaddress hash + currentTime + random 
   		idPrefix = Integer.toHexString(base.hashCode()) + Long.toHexString(System.currentTimeMillis()) + Integer.toHexString(random);
   		
   		
		if (LOG.isLoggable(Level.FINE)) {
			StringBuilder sb = new StringBuilder();
			sb.append(IoProvider.class.getName() + " initialized (");
			
			// disptacher params
			sb.append("countDispatcher=" + countDispatcher + " ");
			sb.append("maxHandles=" + maxHandles + " ");
			sb.append("detachHandleOnNoOps=" + detachHandleOnNoOps + " ");
		 	
			
			// client params
			sb.append("client: directMemory=" + clientReadBufferUseDirect);
			sb.append(" preallocation=" + clientReadBufferPreallocationOn);
			if (clientReadBufferPreallocationOn) {
				sb.append(" preallocationSize=" + DataConverter.toFormatedBytesSize(clientReadBufferPreallocationsize));
				sb.append(" minBufferSize=" + DataConverter.toFormatedBytesSize(clientReadBufferMinsize));
			} 
			
			// server params 
			sb.append(" & server: directMemory=" + serverReadBufferUseDirect);
			sb.append(" preallocation=" + serverReadBufferPreallocationOn);
			if (serverReadBufferPreallocationOn) {
				sb.append(" preallocationSize=" + DataConverter.toFormatedBytesSize(serverReadBufferPreallocationsize));
				sb.append(" minBufferSize=" + DataConverter.toFormatedBytesSize(serverReadBufferMinsize));
			} 
			
			sb.append(")");
			LOG.fine(sb.toString());
		}
     }


	private AbstractMemoryManager sslMemoryManagerServer;
	private AbstractMemoryManager sslMemoryManagerClient;

	private final AtomicInteger nextId = new AtomicInteger();

	

	IoProvider() {
		if (serverReadBufferPreallocationOn) {
			sslMemoryManagerServer = IoSynchronizedMemoryManager.createPreallocatedMemoryManager(serverReadBufferPreallocationsize, serverReadBufferMinsize, serverReadBufferUseDirect);
		} else {
			sslMemoryManagerServer = IoSynchronizedMemoryManager.createNonPreallocatedMemoryManager(serverReadBufferUseDirect);
		}
		
		if (clientReadBufferPreallocationOn) {
			sslMemoryManagerClient = IoSynchronizedMemoryManager.createPreallocatedMemoryManager(clientReadBufferPreallocationsize, clientReadBufferMinsize, clientReadBufferUseDirect);
		} else {
			sslMemoryManagerClient = IoSynchronizedMemoryManager.createNonPreallocatedMemoryManager(clientReadBufferUseDirect);
		}

	}
	
	
	static int getTransferByteBufferMaxSize() {
	    return transferByteBufferMaxSize;
	}
	
	
	static String[] getSSLEngineServerEnabledCipherSuites() {
		return sSLEngineServerEnabledCipherSuites;
	}
	
	static String[] getSSLEngineClientEnabledCipherSuites() {
		return sSLEngineClientEnabledCipherSuites;
	}
	
	static String[] getSSLEngineClientEnabledProtocols() {
		return sSLEngineClientEnabledProtocols;
	}

	static String[] getSSLEngineServerEnabledProtocols() {
		return sSLEngineServerEnabledProtocols;
	}

	
	static Boolean getSSLEngineServerWantClientAuth() {
		return sSLEngineWantClientAuth;
	}
	
	
	static Boolean getSSLEngineServerNeedClientAuth() {
		return sSLEngineNeedClientAuth;
	}

	
	
	static Integer getDefaultClientMaxReadbufferSize() {
		return defaultClientMaxReadbufferSize;
	}
	
	static Integer getDefaultServerMaxReadbufferSize() {
		return defaultServerMaxReadbufferSize;
	}
	
	
	static Integer getDefaultClientMaxWritebufferSize() {
		return defaultClientMaxWritebufferSize;
	}
	
	static Integer getDefaultServerMaxWritebufferSize() {
		return defaultServerMaxWritebufferSize;
	}
	
	static boolean getSuppressSyncFlushWarning() {
	    return suppressSyncFlushWarning;
	}
	
	static boolean getSuppressSyncFlushCompletionHandlerWarning() {
        return suppressSyncFlushCompletionHandlerWarning;
    }
	

	static boolean getSuppressReuseBufferWarning() {
	    return suppressReuseBufferWarning;
	}
	
	static int getServerDispatcherInitialSize() {
		if (countServerDispatcher == null) {
			return getDispatcherInitialSize();
		} else {
			return countServerDispatcher;
		}
	}


	static int getClientDispatcherInitialSize() {
		if (countClientDispatcher == null) {
			return  getDispatcherInitialSize();
		} else {
			return countClientDispatcher;
		}
	}

	
	private static int getDispatcherInitialSize() {
		
	    if (countDispatcher == null) {
		    return 2;
		    
		} else {
			return countDispatcher;
		}
	}

	
    static Integer getMaxHandles() {
    	return maxHandles;
    }
    
    static boolean getDetachHandleOnNoOps() {
    	return detachHandleOnNoOps;
    }
    
    
    static boolean isBypassingWriteAllowed() {
    	return bypassingWriteAllowed;
    }

	/**
	 * Return the version of this implementation. It consists of any string assigned
	 * by the vendor of this implementation and does not have any particular syntax
	 * specified or expected by the Java runtime. It may be compared for equality
	 * with other package version strings used for this implementation
	 * by this vendor for this package.
	 *
	 * @return the version of the implementation
	 */
	public String getImplementationVersion() {
		return "";
	}


    /**
	 * {@inheritDoc}
	 */
	public IoAcceptor createAcceptor(IIoAcceptorCallback callback, InetSocketAddress address, int backlog, Map options) throws IOException {
	
        Boolean isReuseAddress = (Boolean) options.get(IConnection.SO_REUSEADDR);
        if (isReuseAddress == null) {
            isReuseAddress = IS_REUSE_ADDRESS;
        }
        	        
	    
		IoAcceptor acceptor = new IoAcceptor(callback, address, backlog, isReuseAddress);
		for (Entry entry : options.entrySet()) {
			acceptor.setOption(entry.getKey(), entry.getValue());
		}
	
		acceptor.setReceiveBufferIsDirect(serverReadBufferUseDirect);
		acceptor.setReceiveBufferPreallocationMode(serverReadBufferPreallocationOn);
		acceptor.setReceiveBufferPreallocatedMinSize(serverReadBufferMinsize);
		acceptor.setReceiveBufferPreallocationSize(serverReadBufferPreallocationsize);
		
		return acceptor;
	}


	/**
	 * {@inheritDoc}
	 */
	public IoAcceptor createAcceptor(IIoAcceptorCallback callback, InetSocketAddress address, int backlog, Map options, SSLContext sslContext, boolean sslOn) throws IOException {
	    
	    Boolean isReuseAddress = (Boolean) options.get("SO_REUSEADDR");
	    if (isReuseAddress == null) {
	        isReuseAddress = IS_REUSE_ADDRESS;
	    }
	    
	    
		IoAcceptor acceptor = new IoAcceptor(callback, address, backlog, sslContext, sslOn, isReuseAddress);
		for (Entry entry : options.entrySet()) {
			acceptor.setOption(entry.getKey(), entry.getValue());
		}

		acceptor.setReceiveBufferIsDirect(serverReadBufferUseDirect);
		acceptor.setReceiveBufferPreallocationMode(serverReadBufferPreallocationOn);
		acceptor.setReceiveBufferPreallocatedMinSize(serverReadBufferMinsize);
		acceptor.setReceiveBufferPreallocationSize(serverReadBufferPreallocationsize);
		
		return acceptor;
	}


    /**
	 * {@inheritDoc}
	 */
	public IoChainableHandler createClientIoHandler(SocketChannel channel) throws IOException {
		return createIoHandler(true, getGlobalClientDisptacherPool().nextDispatcher(), channel, null, false);
	}


    /**
	 * {@inheritDoc}
	 */
    public IoChainableHandler createSSLClientIoHandler(SocketChannel channel, SSLContext sslContext, boolean sslOn) throws IOException {
    	return createIoHandler(true, getGlobalClientDisptacherPool().nextDispatcher(), channel, sslContext, sslOn);
    }



    /**
	 * {@inheritDoc}
	 */
    IoChainableHandler createIoHandler(boolean isClient, IoSocketDispatcher dispatcher, SocketChannel channel, SSLContext sslContext, boolean sslOn) throws IOException {

    	String connectionId = null;

    	if (isClient) {
    		connectionId = idPrefix + "C" + Integer.toHexString(nextId.incrementAndGet());
    	} else {
    		connectionId = idPrefix + "S" + Integer.toHexString(nextId.incrementAndGet());
    	}

		IoChainableHandler ioHandler = new IoSocketHandler(channel, dispatcher, connectionId);

		// ssl connection?
		if (sslContext != null) {

			AbstractMemoryManager mm = null;
			if (isClient) {
				mm = sslMemoryManagerClient;
			} else {
				mm = sslMemoryManagerServer;
			}

			if (sslOn) {
				ioHandler = new IoSSLHandler(ioHandler, sslContext, isClient, mm);
			} else {
				ioHandler = new IoActivateableSSLHandler(ioHandler, sslContext, isClient, mm);
			}
		}

		return ioHandler;
	}


    /**
     * {@inheritDoc}
     */
    public IoChainableHandler setWriteTransferRate(IoChainableHandler ioHandler, int bytesPerSecond) throws IOException {

    	// unlimited? remove throttling handler if exists
    	if (bytesPerSecond == UNLIMITED) {
    		IoThrottledWriteHandler delayWriter = (IoThrottledWriteHandler) getHandler((IoChainableHandler) ioHandler, IoThrottledWriteHandler.class);
    		if (delayWriter != null) {
    			
    			if (LOG.isLoggable(Level.FINE)) {
    				LOG.fine("write transfer rate is set to unlimited. flushing throttle write handler");
    			}
    			
    			delayWriter.hardFlush();
    			IoChainableHandler successor = delayWriter.getSuccessor();
    			return successor;
    		} else {
    			return ioHandler;
    		}

       	// ...no -> add throttling handler if not exists and set rate
    	} else {
			IoThrottledWriteHandler delayWriter = (IoThrottledWriteHandler) getHandler((IoChainableHandler) ioHandler, IoThrottledWriteHandler.class);
			if (delayWriter == null) {
				delayWriter = new IoThrottledWriteHandler((IoChainableHandler) ioHandler);
			}

			delayWriter.setWriteRateSec(bytesPerSecond);
			return delayWriter;
    	}
	}

    public boolean isSecuredModeActivateable(IoChainableHandler  ioHandler) {
    	IoActivateableSSLHandler activateableHandler = (IoActivateableSSLHandler) getHandler(ioHandler, IoActivateableSSLHandler.class);
		if (activateableHandler != null) {
			return true;
		} else {
			return false;
		}	
    }
  

	public boolean preActivateSecuredMode(IoChainableHandler ioHandler) throws IOException {
		IoActivateableSSLHandler activateableHandler = (IoActivateableSSLHandler) getHandler(ioHandler, IoActivateableSSLHandler.class);
		if (activateableHandler != null) {
			return activateableHandler.preActivateSecuredMode();
		} else {
			throw new IOException("connection is not SSL activatable (non IoActivateableHandler in chain)");
		}
	}

	public void activateSecuredMode(IoChainableHandler ioHandler, ByteBuffer[] buffers) throws IOException {
		ioHandler.hardFlush();

		IoActivateableSSLHandler activateableHandler = (IoActivateableSSLHandler) getHandler((IoChainableHandler) ioHandler, IoActivateableSSLHandler.class);
		if (activateableHandler != null) {
			activateableHandler.activateSecuredMode(buffers);
		} else {
			LOG.warning("connection is not SSL activatable (non IoActivateableHandler in chain");
		}
	}

	public void deactivateSecuredMode(IoChainableHandler ioHandler) throws IOException {
		ioHandler.hardFlush();

		IoActivateableSSLHandler activateableHandler = (IoActivateableSSLHandler) getHandler((IoChainableHandler) ioHandler, IoActivateableSSLHandler.class);
		if (activateableHandler != null) {
			activateableHandler.deactivateSecuredMode();
		} else {
			LOG.warning("connection is not SSL (de)activatable (non IoActivateableHandler in chain");
		}
	}


	static Timer getTimer() {
		return TIMER;
	}

	
	static boolean isUseDirectWriteBuffer() {
		return writeBufferUseDirect;
	}


	static int getReadBufferPreallocationsizeServer() {
		return serverReadBufferPreallocationsize;
	}

	static int getReadBufferMinSizeServer() {
		return serverReadBufferMinsize;
	}


	static boolean isReadBufferPreallocationActivated() {
		return serverReadBufferPreallocationOn;
	}

	


    /**
     * set a option
     *
     * @param socket    the socket
     * @param name      the option name
     * @param value     the option value
     * @throws IOException if an exception occurs
     */
	static void setOption(Socket socket, String name, Object value) throws IOException {

		if (name.equals(SO_SNDBUF)) {
			socket.setSendBufferSize(asInt(value));

		} else if (name.equals(SO_REUSEADDR)) {
			socket.setReuseAddress(asBoolean(value));

		} else if (name.equals(SO_TIMEOUT)) {
			socket.setSoTimeout(asInt(value));

		} else if (name.equals(SO_RCVBUF)) {
			socket.setReceiveBufferSize(asInt(value));

		} else if (name.equals(SO_KEEPALIVE)) {
			socket.setKeepAlive(asBoolean(value));

		} else if (name.equals(SO_LINGER)) {
			try {
				socket.setSoLinger(true, asInt(value));
			} catch (ClassCastException cce) {
				socket.setSoLinger(Boolean.FALSE, 0);
			}

		} else if (name.equals(TCP_NODELAY)) {
			socket.setTcpNoDelay(asBoolean(value));


		} else {
			LOG.warning("option " + name + " is not supported");
		}
	}


	/**
	 * get a option
	 *
	 * @param socket    the socket
	 * @param name      the option name
	 * @return the option value
     * @throws IOException if an exception occurs
	 */
	static Object getOption(Socket socket, String name) throws IOException {

		if (name.equals(SO_SNDBUF)) {
			return socket.getSendBufferSize();

		} else if (name.equals(SO_REUSEADDR)) {
			return socket.getReuseAddress();

		} else if (name.equals(SO_RCVBUF)) {
			return socket.getReceiveBufferSize();

		} else if (name.equals(SO_KEEPALIVE)) {
			return socket.getKeepAlive();

		} else if (name.equals(SO_TIMEOUT)) {
			return socket.getSoTimeout();

		} else if (name.equals(TCP_NODELAY)) {
			return socket.getTcpNoDelay();

		} else if (name.equals(SO_LINGER)) {
			return socket.getSoLinger();


		} else {
			LOG.warning("option " + name + " is not supported");
			return null;
		}
	}



	private static int asInt(Object obj) {
		if (obj instanceof Integer) {
			return (Integer) obj;
		}

		return Integer.parseInt(obj.toString());
	}

	private static boolean asBoolean(Object obj) {
		if (obj instanceof Boolean) {
			return (Boolean) obj;
		}

		return Boolean.parseBoolean(obj.toString());
	}



	@SuppressWarnings("unchecked")
	private IoChainableHandler getHandler(IoChainableHandler head, Class clazz) {
		IoChainableHandler handler = head;
		do {
			if (handler.getClass() == clazz) {
				return handler;
			}

			handler = handler.getSuccessor();
		} while (handler != null);

		return null;
	}


	static synchronized IoSocketDispatcherPool getGlobalClientDisptacherPool() {
		if (globalClientDispatcherPool == null) {
			globalClientDispatcherPool = new IoSocketDispatcherPool("ClientGlb", getClientDispatcherInitialSize());
			
			globalClientDispatcherPool.setReceiveBufferIsDirect(clientReadBufferUseDirect);
			globalClientDispatcherPool.setReceiveBufferPreallocationMode(clientReadBufferPreallocationOn);
			globalClientDispatcherPool.setReceiveBufferPreallocatedMinSize(clientReadBufferMinsize);
			globalClientDispatcherPool.setReceiveBufferPreallocationSize(clientReadBufferPreallocationsize);
		}
		
		return globalClientDispatcherPool;
	}
	
	
	
	private static Integer readIntProperty(String key) { 
		try {
			String property = readProperty(key);
			if (property != null) {
				return Integer.parseInt(property);
			} else {
				return null;
			}
		} catch (Exception e) {
			LOG.warning("invalid value for system property " + key + ": " + 
				    System.getProperty(key) + " " + e.toString());
			return null;
		}
	}

	private static Integer readIntProperty(String key, Integer dflt) { 
		try {
			String property = readProperty(key);
			if (property != null) {
				return Integer.parseInt(property);
			} else {
				return dflt;
			}
		} catch (Exception e) {
			LOG.warning("invalid value for system property " + key + ": "
					+ System.getProperty(key) + " (valid is int)"
					+ " using " + dflt);
			return null;
		}
	}
	
	
	private static Boolean readBooleanProperty(String key, String dflt) { 
		try {
			String property = readProperty(key);
			if (property != null) {
				return Boolean.parseBoolean(property);
			} else {
				if (dflt == null) {
					return null;
				} else {
					return Boolean.parseBoolean(dflt);
				}
			}
		} catch (Exception e) {
			LOG.warning("invalid value for system property " + key + ": "
					+ System.getProperty(key) + " (valid is true|false)"
					+ " using " + dflt);
			if (dflt != null) {
				return Boolean.parseBoolean(dflt);
			} else {
				return null;
			}
		}
	}
	
	
	private static String[] readStringArrayProperty(String key, String[] dflt) { 
		String property = readProperty(key);
		if (property != null) {
			String[] props = property.split(",");
			String[] result = new String[props.length];
			for (int i = 0; i < props.length; i++) {
				result[i] = props[i].trim(); 
			}
			return result;
		} else {
			return dflt;
		}
	}

	
	private static String readProperty(String key) { 
		try {
			return System.getProperty(key);
		} catch (Exception e) {
			LOG.warning("invalid value for system property " + key + " " + e.toString());
			return null;
		}
	}	
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy