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

org.jboss.remoting.transport.multiplex.VirtualServerSocket Maven / Gradle / Ivy

There is a newer version: 5.0.29.Final
Show newest version
/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* 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.
*/

/*
 * Created on Jul 23, 2005
 */

package org.jboss.remoting.transport.multiplex;

import org.jboss.logging.Logger;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.Serializable;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.nio.channels.ServerSocketChannel;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;


/**
 * VirtualServerSocket is one of the two implementations of a server socket in the
 * Multiplex project.  Each VirtualServerSocket belongs to an existing virtual
 * socket group, and each VirtualScoket it creates is added to that virtual socket
 * group. For more details, see the Multiplex documentation on
 * the labs.jboss.org web site.
 *
 * 

* Most of the methods in VirtualServerSocket override those in its parent class, * java.net.ServerSocket. For method descriptions, see the ServerSocket * javadoc. * *

* Copyright (c) 2005 *

* @author Ron Sigal */ public class VirtualServerSocket extends ServerSocket implements Serializable { private static final Logger log = Logger.getLogger(VirtualServerSocket.class); private List acceptingThreads = Collections.synchronizedList(new LinkedList()); private Map configuration = new HashMap(); private MultiplexingManager manager; private MultiplexingInputStream is; private MultiplexingInputStream cis; private Protocol protocol; private Socket actualSocket; private int timeout; private boolean bound = false; private boolean connected = false; private boolean closed = false; private Socket dummySocket; private static final long serialVersionUID = -5320724929164012313L; ////////////////////////////////////////////////////////////////////////////////////////////////// /// The following constructors duplicate those of the parent class ServerSocket '/// ////////////////////////////////////////////////////////////////////////////////////////////////// /** * @throws java.io.IOException */ public VirtualServerSocket() throws IOException { } /** * * See superclass javadoc. * * @param port * @throws IOException */ public VirtualServerSocket(int port) throws IOException { bind(new InetSocketAddress(port)); log.debug("created VirtualServerSocket: " + toString()); } /** * See superclass javadoc. * * @param port * @param backlog * @throws java.io.IOException */ public VirtualServerSocket(int port, int backlog) throws IOException { this(port); log.warn("backlog parameter is ignored"); log.debug("created VirtualServerSocket: " + toString()); } /** * See superclass javadoc. * * @param port * @param backlog * @param bindAddr * @throws java.io.IOException */ public VirtualServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException { bind(new InetSocketAddress(bindAddr, port)); log.warn("backlog parameter is ignored"); log.debug("created VirtualServerSocket: " + toString()); } ////////////////////////////////////////////////////////////////////////////////////////////////// /// The following constructors are particular to VirtualServerSocket '/// ////////////////////////////////////////////////////////////////////////////////////////////////// /** * See superclass javadoc. * @param configuration */ public VirtualServerSocket(VirtualSocket socket, Map configuration) throws IOException { this.actualSocket = socket.getActualSocket(); if (configuration != null) this.configuration.putAll(configuration); manager = socket.getManager(); manager.incrementReferences(); bind(new InetSocketAddress(socket.getLocalAddress(), socket.getLocalPort())); log.debug("created VirtualServerSocket: " + toString()); } /** * * See superclass javadoc. * * @param timeout * @param configuration * @param port * @throws IOException */ public VirtualServerSocket(InetSocketAddress remoteAddress, InetSocketAddress localAddress, int timeout, Map configuration) throws IOException { if (configuration != null) this.configuration.putAll(configuration); connect(remoteAddress, localAddress, timeout); log.debug("created VirtualServerSocket: " + toString()); } ////////////////////////////////////////////////////////////////////////////////////////////////// /// The following methods are required of any ServerSocket '/// ////////////////////////////////////////////////////////////////////////////////////////////////// /* ok: public void bind(SocketAddress endpoint) throws IOException; ok: public void bind(SocketAddress endpoint, int backlog) throws IOException; ok: public InetAddress getInetAddress(); ok: public int getLocalPort(); ok: public SocketAddress getLocalSocketAddress(); ok: public Socket accept() throws IOException; ok: public void close() throws IOException; ok: public ServerSocketChannel getChannel(); ok: public boolean isBound(); ok: public boolean isClosed(); ok: public void setSoTimeout(int timeout) throws SocketException; ok: public int getSoTimeout() throws IOException; ok: public void setReuseAddress(boolean on) throws SocketException; ok: public boolean getReuseAddress() throws SocketException; ok: public String toString(); ok: public void setReceiveBufferSize(int size) throws SocketException; ok: public int getReceiveBufferSize() throws SocketException; */ /** * See superclass javadoc. */ public synchronized Socket accept() throws IOException { log.debug("entering accept()"); long start = System.currentTimeMillis(); int timeout = getSoTimeout(); int timeLeft = 0; if (isClosed()) throw new SocketException("Socket is closed"); if (!isBound()) throw new SocketException("Socket is not bound yet"); SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkAccept(actualSocket.getInetAddress().getHostAddress(), actualSocket.getPort()); } Thread currentThread = Thread.currentThread(); acceptingThreads.add(currentThread); VirtualSocket virtualSocket = null; try { if (timeout > 0) if ((timeLeft = timeout - (int) (System.currentTimeMillis() - start)) <= 0) { log.error("timed out"); throw new SocketTimeoutException("Accept timed out"); } log.debug("timeLeft: " + timeLeft); SocketId clientPort = protocol.acceptConnect(is, timeLeft); log.debug("clientPort: " + clientPort.getPort()); virtualSocket = new VirtualSocket(manager, clientPort, configuration); manager.incrementReferences(); int localPort = virtualSocket.getLocalVirtualPort(); protocol.answerConnect((MultiplexingOutputStream) virtualSocket.getOutputStream(), localPort); return virtualSocket; } catch (IOException e) { if (e instanceof InterruptedIOException || "Socket closed".equals(e.getMessage()) || "An existing connection was forcibly closed by the remote host".equals(e.getMessage())) log.debug(e); else log.error(e); if (virtualSocket != null) virtualSocket.close(); if (isClosed()) throw new SocketException("Socket closed"); if (e instanceof SocketTimeoutException) throw new SocketTimeoutException("Accept timed out"); throw e; } finally { acceptingThreads.remove(currentThread); if (isClosed()) { if (virtualSocket != null) virtualSocket.close(); throw new SocketException("Socket closed"); } } } /** * See superclass javadoc. */ public void bind(SocketAddress socketAddress) throws IOException { bind(socketAddress, 1); } /** * See superclass javadoc. */ public void bind(SocketAddress socketAddress, int backlog) throws IOException { if (backlog != 1) { log.warn("backlog != 1: ignored"); } if (isClosed()) throw new SocketException("Socket is closed"); if (isBound()) throw new SocketException("Already bound"); if (socketAddress == null) socketAddress = new InetSocketAddress(0); if (!(socketAddress instanceof InetSocketAddress)) throw new IllegalArgumentException("Unsupported address type"); InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress; if (inetSocketAddress.isUnresolved()) throw new SocketException("Unresolved address"); SecurityManager security = System.getSecurityManager(); if (security != null) security.checkListen(inetSocketAddress.getPort()); if (manager == null) { manager = MultiplexingManager.getaManagerByLocalAddress(inetSocketAddress, configuration); actualSocket = manager.getSocket(); } try { bound = true; is = manager.registerServerSocket(this); cis = manager.getAnInputStream(SocketId.SERVER_SOCKET_CONNECT_ID, null); is.setTimeout(timeout); cis.setTimeout(timeout); if (manager.isConnected()) { protocol = manager.getProtocol(); // remote MultiplexingManager might be shutting down and refuse to register ServerSocket protocol.registerRemoteServerSocket(getSoTimeout()); connected = true; } } catch (IOException e) { bound = false; if (manager.isServerSocketRegistered()) manager.unRegisterServerSocket(this); throw e; } log.debug(toString()); } /** * See superclass javadoc. */ public void close() throws IOException { if (isClosed()) return; closed = true; // Try once to interrupt accepting threads. if (!acceptingThreads.isEmpty()) { // We get a copy of acceptingThreads to avoid a ConcurrentModificationException when a thread // removes itself from acceptingThreads. LinkedList threads = new LinkedList(acceptingThreads); Iterator it = threads.iterator(); while (it.hasNext()) { Thread t = (Thread) it.next(); t.interrupt(); log.debug("interrupting accepting thread: " + t.getName()); } if (!acceptingThreads.isEmpty()) { MultiplexingManager.addToPendingActions(new PendingClose(this)); } } // We want the unregister request to go out to the remote MultiplexingManager first. // This way, if the local unregister request causes the local MultiplexingManager to // shut down, the remote MultiplexingManager will get the unregisterRemoteServerSocket // request before it gets the shutdown manager request. if (protocol != null) protocol.unregisterRemoteServerSocket(); if (manager != null) manager.unRegisterServerSocket(this); } /** * See superclass javadoc. */ public InetAddress getInetAddress() { if (actualSocket == null) return null; return actualSocket.getInetAddress(); } /** * See superclass javadoc. */ public int getLocalPort() { if (actualSocket == null) return -1; return actualSocket.getLocalPort(); } /** * See superclass javadoc. */ public ServerSocketChannel getChannel() { return null; } /** * See superclass javadoc. */ public SocketAddress getLocalSocketAddress() { if (actualSocket == null) return null; return actualSocket.getLocalSocketAddress(); } /** * See superclass javadoc. */ public int getReceiveBufferSize() throws SocketException { if (actualSocket == null) { if (dummySocket == null) dummySocket = new Socket(); return dummySocket.getReceiveBufferSize(); } return actualSocket.getReceiveBufferSize(); } /** * See superclass javadoc. */ public boolean getReuseAddress() throws SocketException { if (actualSocket == null) return true; else return actualSocket.getReuseAddress(); } /** * See superclass javadoc. */ public int getSoTimeout() throws SocketException { if (isClosed()) throw new SocketException("Socket is closed"); return timeout; } /** * See superclass javadoc. */ public boolean isBound() { return bound; } /** * See superclass javadoc. */ public boolean isClosed() { return closed; } /** * See superclass javadoc. */ public void setReceiveBufferSize (int size) throws SocketException { if (actualSocket != null) actualSocket.setReceiveBufferSize(size); } /** * See superclass javadoc. */ public void setReuseAddress(boolean on) throws SocketException { if (actualSocket != null) actualSocket.setReuseAddress(on); } /** * See superclass javadoc. */ public void setSoTimeout(int timeout) throws SocketException { if (isClosed()) throw new SocketException("Socket is closed"); if (timeout < 0) throw new IllegalArgumentException("timeout can't be negative"); this.timeout = timeout; if (is != null) is.setTimeout(timeout); if (cis != null) cis.setTimeout(timeout); } /** * See superclass javadoc. */ public String toString() { StringBuffer answer = new StringBuffer().append("VirtualServerSocket["); if (actualSocket == null) answer.append("unbound"); else answer.append(actualSocket.toString()); return answer.append("]").toString(); } ////////////////////////////////////////////////////////////////////////////////////////////////// /// The following methods are specific to VirtualServerSocket '/// ////////////////////////////////////////////////////////////////////////////////////////////////// /** * See superclass javadoc. */ public void connect(SocketAddress remoteAddress) throws IOException { connect(remoteAddress, null, timeout); } /** * Connects this socket to the server. * * See superclass javadoc. */ public void connect(SocketAddress remoteAddress, SocketAddress localAddress) throws IOException { connect(remoteAddress, localAddress, timeout); } /** * See superclass javadoc. */ public void connect(SocketAddress remoteAddress, SocketAddress localAddress, int timeout) throws IOException { long start = System.currentTimeMillis(); int timeLeft = 0; if (remoteAddress == null) throw new IllegalArgumentException("connect: The address can't be null"); if (timeout < 0) throw new IllegalArgumentException("connect: timeout can't be negative"); if (isClosed()) throw new SocketException("Socket is closed"); if (!(remoteAddress instanceof InetSocketAddress)) throw new IllegalArgumentException("Unsupported address type"); InetSocketAddress remoteInetSocketAddress = (InetSocketAddress) remoteAddress; SecurityManager security = System.getSecurityManager(); if (security != null) { if (remoteInetSocketAddress.isUnresolved()) security.checkConnect(remoteInetSocketAddress.getHostName(), remoteInetSocketAddress.getPort()); else security.checkConnect(remoteInetSocketAddress.getAddress().getHostAddress(), remoteInetSocketAddress.getPort()); } // Binding entails getting a MultiplexingManager, which might already be connected, // thereby putting the ServerSocket in a connected state. Therefore, we allow connect() to be // called on a connected ServerSocket, as long as the host to which it is to be connected // is the same as the host to which it is already connected. if (isConnected()) if (getRemoteAddress().equals(remoteInetSocketAddress.getAddress())) return; else throw new SocketException("already connected"); if (manager == null) { if (timeout > 0) if ((timeLeft = timeout - (int) (System.currentTimeMillis() - start)) <= 0) throw new SocketTimeoutException("connect timed out"); if (localAddress == null) manager = MultiplexingManager.getaManagerByRemoteAddress(remoteInetSocketAddress, timeLeft, configuration); else { InetSocketAddress localInetSocketAddress = (InetSocketAddress) localAddress; manager = MultiplexingManager.getaManagerByAddressPair(remoteInetSocketAddress, localInetSocketAddress, timeLeft, configuration); } } actualSocket = manager.getSocket(); try { if (!isBound()) { log.debug("calling registerServerSocket()"); is = manager.registerServerSocket(this); cis = manager.getAnInputStream(SocketId.SERVER_SOCKET_CONNECT_ID, null); is.setTimeout(this.timeout); cis.setTimeout(this.timeout); bound = true; } // If the manager is not connected, we need to connect to the remote MasterServerSocket, which // will create a real socket and a MultiplexingManager to wrap it. if (!manager.isConnected()) { if (timeout > 0) if ((timeLeft = timeout - (int) (System.currentTimeMillis() - start)) <= 0) throw new SocketTimeoutException("connect timed out"); manager.connect(remoteInetSocketAddress, timeLeft); protocol = manager.getProtocol(); if (timeout > 0) if ((timeLeft = timeout - (int) (System.currentTimeMillis() - start)) <= 0) throw new SocketTimeoutException("connect timed out"); cis.setTimeout(timeout); protocol.connect(cis, SocketId.SERVER_SOCKET_ID, timeLeft); // Remote MultiplexingManager might be shutting down and refuse to register ServerSocket. // If so, registerRemoteServerSocket() will throw an IOException if (timeout > 0) if ((timeLeft = timeout - (int) (System.currentTimeMillis() - start)) <= 0) throw new SocketTimeoutException("connect timed out"); } else protocol = manager.getProtocol(); if (timeout > 0) if ((timeLeft = timeout - (int) (System.currentTimeMillis() - start)) <= 0) throw new SocketTimeoutException("connect timed out"); protocol.registerRemoteServerSocket(timeLeft); } catch (IOException e) { log.error("i/o exception in VirtualServerSocket.connect()", e); if (manager.isServerSocketRegistered()) manager.unRegisterServerSocket(this); if (e instanceof SocketTimeoutException) throw new SocketTimeoutException("connect timed out"); throw e; } finally { if (cis != null) cis.setTimeout(this.timeout); } connected = true; log.debug(toString()); } /** * @return */ public MultiplexingManager getMultiplexingManager() { return manager; } /** * See superclass javadoc. */ public boolean isConnected() { return connected; } /** * See superclass javadoc. */ public InetAddress getRemoteAddress() { if (actualSocket == null) return null; return actualSocket.getInetAddress(); } /** * See superclass javadoc. */ public int getRemotePort() { if (actualSocket == null) return 0; return actualSocket.getPort(); } /** * See superclass javadoc. */ public void setConfiguration(Map configuration) { this.configuration.putAll(configuration); } /** * */ protected void doClose() { // We get a copy of acceptingThreads to avoid a ConcurrentModificationException when a thread // removes itself from acceptingThreads. LinkedList threads = new LinkedList(acceptingThreads); Iterator it = threads.iterator(); while (it.hasNext()) { Thread t = (Thread) it.next(); t.interrupt(); log.debug("interrupting accepting thread: " + t.getName()); // Make sure the accepting thread caught the interrupt. while (acceptingThreads.contains(t)) { try { log.debug("waiting for accepting thread to catch interrupt: " + t.getName()); Thread.sleep(500); t.interrupt(); log.debug("interrupting accepting thread: " + t.getName()); } catch (InterruptedException ignored) {} } } } protected class PendingClose extends PendingAction { public PendingClose(Object o) { super(o); } public void doAction() { ((VirtualServerSocket) o).doClose(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy