/******************************************************************************* * Copyright (c) 2012 Composent, Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Composent, Inc. - initial API and implementation ******************************************************************************/ package org.eclipse.ecf.provider.generic; import java.io.IOException; import java.net.InetAddress; import java.net.Socket; import javax.net.ssl.SSLServerSocket; import javax.net.ssl.SSLServerSocketFactory; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.ecf.core.util.Trace; import org.eclipse.ecf.internal.provider.ECFProviderDebugOptions; import org.eclipse.ecf.internal.provider.ProviderPlugin; import org.eclipse.ecf.provider.comm.tcp.ISocketAcceptHandler; import org.eclipse.ecf.provider.comm.tcp.Server; /** * @since 4.3 */ public class SSLServerSOContainerGroup extends SOContainerGroup implements ISocketAcceptHandler { public static final int DEFAULT_BACKLOG = 50; public static final String DEFAULT_GROUP_NAME = SSLServerSOContainerGroup.class.getName(); private int port = 0; private int backlog = DEFAULT_BACKLOG; SSLServerSocket serverSocket; private boolean isOnTheAir = false; private ThreadGroup threadGroup; private InetAddress inetAddress; private Thread listenerThread; public SSLServerSOContainerGroup(String name, ThreadGroup group, int port, int backlog, InetAddress inetAddress) { super(name); this.threadGroup = group; this.port = port; this.backlog = backlog; this.inetAddress = inetAddress; listenerThread = setupListener(); } public SSLServerSOContainerGroup(String name, ThreadGroup group, int port, int backlog) { this(name, group, port, backlog, null); } /** * @param name name * @param group thread group to use to create thread * @param port port * @param bindAddress bind address * @since 4.4 */ public SSLServerSOContainerGroup(String name, ThreadGroup group, int port, InetAddress bindAddress) { this(name, group, port, Server.DEFAULT_BACKLOG, bindAddress); } public SSLServerSOContainerGroup(String name, ThreadGroup group, int port) { this(name, group, port, DEFAULT_BACKLOG); } public SSLServerSOContainerGroup(String name, int port) { this(name, null, port); } public SSLServerSOContainerGroup(int port) { this(DEFAULT_GROUP_NAME, null, port); } /** * @param name name * @param group thread group to use * @param sslServerSocket the ssl server socket * @since 4.6 */ public SSLServerSOContainerGroup(String name, ThreadGroup group, SSLServerSocket sslServerSocket) { super(name); this.threadGroup = group; this.serverSocket = sslServerSocket; this.port = serverSocket.getLocalPort(); this.listenerThread = setupListener(); } protected void trace(String msg) { Trace.trace(ProviderPlugin.PLUGIN_ID, ECFProviderDebugOptions.DEBUG, msg); } protected void traceStack(String msg, Throwable e) { Trace.catching(ProviderPlugin.PLUGIN_ID, ECFProviderDebugOptions.EXCEPTIONS_CATCHING, SSLServerSOContainerGroup.class, msg, e); } public synchronized void putOnTheAir() throws IOException { trace("SSLServerSOContainerGroup at port " + port + " on the air"); //$NON-NLS-1$ //$NON-NLS-2$ if (this.serverSocket == null) { SSLServerSocketFactory socketFactory = ProviderPlugin.getDefault().getSSLServerSocketFactory(); if (socketFactory == null) throw new IOException("Cannot get SSLServerSocketFactory to create SSLServerSocket"); //$NON-NLS-1$ serverSocket = (SSLServerSocket) ((this.inetAddress == null) ? socketFactory.createServerSocket(this.port, this.backlog) : socketFactory.createServerSocket(this.port, this.backlog, this.inetAddress)); } port = serverSocket.getLocalPort(); isOnTheAir = true; listenerThread.start(); } public synchronized boolean isOnTheAir() { return isOnTheAir; } public synchronized void takeOffTheAir() { trace("Taking " + getName() + " off the air."); //$NON-NLS-1$ //$NON-NLS-2$ if (listenerThread != null) { listenerThread.interrupt(); listenerThread = null; } if (threadGroup != null) { threadGroup.interrupt(); threadGroup = null; } if (this.serverSocket != null) { try { this.serverSocket.close(); } catch (IOException e) { Trace.catching("org.eclipse.ecf.provider", ECFProviderDebugOptions.CONNECTION, SSLServerSOContainerGroup.class, "takeOffTheAir", e); //$NON-NLS-1$ //$NON-NLS-2$ } this.serverSocket = null; } isOnTheAir = false; } public synchronized int getPort() { return port; } public synchronized String toString() { return super.toString() + ";port:" + port; //$NON-NLS-1$ } protected Thread setupListener() { return new Thread(threadGroup, new Runnable() { public void run() { while (true) { try { handleAccept(serverSocket.accept()); } catch (Exception e) { traceStack("Exception in accept", e); //$NON-NLS-1$ // If we get an exception on accept(), we should just // exit break; } } debug("SSLServerSOContaienrGroup closing listener normally."); //$NON-NLS-1$ } }, "SSLServerSOContainerGroup(" + port + ")"); //$NON-NLS-1$ //$NON-NLS-2$ } /** * @param aSocket socket * @throws Exception if some problem with handling accept * @since 4.7 */ protected void handleSyncAccept(final Socket aSocket) throws Exception { super.handleAccept(aSocket); } public void handleAccept(final Socket aSocket) { new Thread(threadGroup, new Runnable() { public void run() { try { debug("accept:" + aSocket.getInetAddress()); //$NON-NLS-1$ handleSyncAccept(aSocket); } catch (Exception e) { traceStack("Unexpected exception in handleAccept...closing", //$NON-NLS-1$ e); try { aSocket.close(); } catch (IOException e1) { ProviderPlugin.getDefault().log(new Status(IStatus.ERROR, ProviderPlugin.PLUGIN_ID, IStatus.ERROR, "accept.close", e1)); //$NON-NLS-1$ } } } }).start(); } protected void debug(String msg) { Trace.trace(ProviderPlugin.PLUGIN_ID, ECFProviderDebugOptions.CONNECTION, msg); } }