blob: 4b24c6b8376789fb1f4ed62166a9991e00be78d7 [file] [log] [blame]
/*
* Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.corba.se.impl.transport;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import com.sun.corba.se.pept.broker.Broker;
import com.sun.corba.se.pept.encoding.InputObject;
import com.sun.corba.se.pept.encoding.OutputObject;
import com.sun.corba.se.pept.protocol.MessageMediator;
import com.sun.corba.se.pept.transport.Acceptor;
import com.sun.corba.se.pept.transport.Connection;
import com.sun.corba.se.pept.transport.ContactInfo;
import com.sun.corba.se.pept.transport.EventHandler;
import com.sun.corba.se.pept.transport.InboundConnectionCache;
import com.sun.corba.se.pept.transport.Selector;
import com.sun.corba.se.spi.extension.RequestPartitioningPolicy;
import com.sun.corba.se.spi.ior.IORTemplate;
import com.sun.corba.se.spi.ior.TaggedProfileTemplate;
import com.sun.corba.se.spi.ior.iiop.IIOPAddress ;
import com.sun.corba.se.spi.ior.iiop.IIOPFactories;
import com.sun.corba.se.spi.ior.iiop.IIOPProfileTemplate ;
import com.sun.corba.se.spi.ior.iiop.GIOPVersion ;
import com.sun.corba.se.spi.ior.iiop.AlternateIIOPAddressComponent;
import com.sun.corba.se.spi.logging.CORBALogDomains;
import com.sun.corba.se.spi.orb.ORB;
import com.sun.corba.se.spi.orbutil.threadpool.Work;
import com.sun.corba.se.spi.protocol.CorbaMessageMediator;
import com.sun.corba.se.spi.transport.CorbaAcceptor;
import com.sun.corba.se.spi.transport.CorbaConnection;
import com.sun.corba.se.spi.transport.SocketInfo;
import com.sun.corba.se.spi.transport.SocketOrChannelAcceptor;
import com.sun.corba.se.impl.encoding.CDRInputObject;
import com.sun.corba.se.impl.encoding.CDROutputObject;
import com.sun.corba.se.impl.logging.ORBUtilSystemException;
import com.sun.corba.se.impl.oa.poa.Policies; // REVISIT impl/poa specific
import com.sun.corba.se.impl.orbutil.ORBConstants;
import com.sun.corba.se.impl.orbutil.ORBUtility;
// BEGIN Legacy support.
import com.sun.corba.se.spi.legacy.connection.LegacyServerSocketEndPointInfo;
// END Legacy support.
/**
* @author Harold Carr
*/
public class SocketOrChannelAcceptorImpl
extends
EventHandlerBase
implements
CorbaAcceptor,
SocketOrChannelAcceptor,
Work,
// BEGIN Legacy
SocketInfo,
LegacyServerSocketEndPointInfo
// END Legacy
{
protected ServerSocketChannel serverSocketChannel;
protected ServerSocket serverSocket;
protected int port;
protected long enqueueTime;
protected boolean initialized;
protected ORBUtilSystemException wrapper ;
protected InboundConnectionCache connectionCache;
// BEGIN Legacy
protected String type = "";
protected String name = "";
protected String hostname;
protected int locatorPort;
// END Legacy
public SocketOrChannelAcceptorImpl(ORB orb)
{
this.orb = orb;
wrapper = ORBUtilSystemException.get( orb,
CORBALogDomains.RPC_TRANSPORT ) ;
setWork(this);
initialized = false;
// BEGIN Legacy support.
this.hostname = orb.getORBData().getORBServerHost();
this.name = LegacyServerSocketEndPointInfo.NO_NAME;
this.locatorPort = -1;
// END Legacy support.
}
public SocketOrChannelAcceptorImpl(ORB orb, int port)
{
this(orb);
this.port = port;
}
// BEGIN Legacy support.
public SocketOrChannelAcceptorImpl(ORB orb, int port,
String name, String type)
{
this(orb, port);
this.name = name;
this.type = type;
}
// END Legacy support.
////////////////////////////////////////////////////
//
// pept.transport.Acceptor
//
public boolean initialize()
{
if (initialized) {
return false;
}
if (orb.transportDebugFlag) {
dprint(".initialize: " + this);
}
InetSocketAddress inetSocketAddress = null;
try {
if (orb.getORBData().getListenOnAllInterfaces().equals(ORBConstants.LISTEN_ON_ALL_INTERFACES)) {
inetSocketAddress = new InetSocketAddress(port);
} else {
String host = orb.getORBData().getORBServerHost();
inetSocketAddress = new InetSocketAddress(host, port);
}
serverSocket = orb.getORBData().getSocketFactory()
.createServerSocket(type, inetSocketAddress);
internalInitialize();
} catch (Throwable t) {
throw wrapper.createListenerFailed( t, Integer.toString(port) ) ;
}
initialized = true;
return true;
}
protected void internalInitialize()
throws Exception
{
// Determine the listening port (for the IOR).
// This is important when using emphemeral ports (i.e.,
// when the port value to the constructor is 0).
port = serverSocket.getLocalPort();
// Register with transport (also sets up monitoring).
orb.getCorbaTransportManager().getInboundConnectionCache(this);
// Finish configuation.
serverSocketChannel = serverSocket.getChannel();
if (serverSocketChannel != null) {
setUseSelectThreadToWait(
orb.getORBData().acceptorSocketUseSelectThreadToWait());
serverSocketChannel.configureBlocking(
! orb.getORBData().acceptorSocketUseSelectThreadToWait());
} else {
// Configure to use listener and reader threads.
setUseSelectThreadToWait(false);
}
setUseWorkerThreadForEvent(
orb.getORBData().acceptorSocketUseWorkerThreadForEvent());
}
public boolean initialized()
{
return initialized;
}
public String getConnectionCacheType()
{
return this.getClass().toString();
}
public void setConnectionCache(InboundConnectionCache connectionCache)
{
this.connectionCache = connectionCache;
}
public InboundConnectionCache getConnectionCache()
{
return connectionCache;
}
public boolean shouldRegisterAcceptEvent()
{
return true;
}
public void accept()
{
try {
SocketChannel socketChannel = null;
Socket socket = null;
if (serverSocketChannel == null) {
socket = serverSocket.accept();
} else {
socketChannel = serverSocketChannel.accept();
socket = socketChannel.socket();
}
orb.getORBData().getSocketFactory()
.setAcceptedSocketOptions(this, serverSocket, socket);
if (orb.transportDebugFlag) {
dprint(".accept: " +
(serverSocketChannel == null
? serverSocket.toString()
: serverSocketChannel.toString()));
}
CorbaConnection connection =
new SocketOrChannelConnectionImpl(orb, this, socket);
if (orb.transportDebugFlag) {
dprint(".accept: new: " + connection);
}
// NOTE: The connection MUST be put in the cache BEFORE being
// registered with the selector. Otherwise if the bytes
// are read on the connection it will attempt a time stamp
// but the cache will be null, resulting in NPE.
// A connection needs to be timestamped before putting to the cache.
// Otherwise the newly created connection (with 0 timestamp) could be
// incorrectly reclaimed by concurrent reclaim() call OR if there
// will be no events on this connection then it could be reclaimed
// by upcoming reclaim() call.
getConnectionCache().stampTime(connection);
getConnectionCache().put(this, connection);
if (connection.shouldRegisterServerReadEvent()) {
Selector selector = orb.getTransportManager().getSelector(0);
if (selector != null) {
if (orb.transportDebugFlag) {
dprint(".accept: registerForEvent: " + connection);
}
selector.registerForEvent(connection.getEventHandler());
}
}
getConnectionCache().reclaim();
} catch (IOException e) {
if (orb.transportDebugFlag) {
dprint(".accept:", e);
}
Selector selector = orb.getTransportManager().getSelector(0);
if (selector != null) {
selector.unregisterForEvent(this);
// REVISIT - need to close - recreate - then register new one.
selector.registerForEvent(this);
// NOTE: if register cycling we do not want to shut down ORB
// since local beans will still work. Instead one will see
// a growing log file to alert admin of problem.
}
}
}
public void close ()
{
try {
if (orb.transportDebugFlag) {
dprint(".close->:");
}
Selector selector = orb.getTransportManager().getSelector(0);
if (selector != null) {
selector.unregisterForEvent(this);
}
if (serverSocketChannel != null) {
serverSocketChannel.close();
}
if (serverSocket != null) {
serverSocket.close();
}
} catch (IOException e) {
if (orb.transportDebugFlag) {
dprint(".close:", e);
}
} finally {
if (orb.transportDebugFlag) {
dprint(".close<-:");
}
}
}
public EventHandler getEventHandler()
{
return this;
}
////////////////////////////////////////////////////
//
// CorbaAcceptor
//
public String getObjectAdapterId()
{
return null;
}
public String getObjectAdapterManagerId()
{
return null;
}
public void addToIORTemplate(IORTemplate iorTemplate,
Policies policies,
String codebase)
{
Iterator iterator = iorTemplate.iteratorById(
org.omg.IOP.TAG_INTERNET_IOP.value);
String hostname = orb.getORBData().getORBServerHost();
if (iterator.hasNext()) {
// REVISIT - how does this play with legacy ORBD port exchange?
IIOPAddress iiopAddress =
IIOPFactories.makeIIOPAddress(orb, hostname, port);
AlternateIIOPAddressComponent iiopAddressComponent =
IIOPFactories.makeAlternateIIOPAddressComponent(iiopAddress);
while (iterator.hasNext()) {
TaggedProfileTemplate taggedProfileTemplate =
(TaggedProfileTemplate) iterator.next();
taggedProfileTemplate.add(iiopAddressComponent);
}
} else {
GIOPVersion version = orb.getORBData().getGIOPVersion();
int templatePort;
if (policies.forceZeroPort()) {
templatePort = 0;
} else if (policies.isTransient()) {
templatePort = port;
} else {
templatePort = orb.getLegacyServerSocketManager()
.legacyGetPersistentServerPort(SocketInfo.IIOP_CLEAR_TEXT);
}
IIOPAddress addr =
IIOPFactories.makeIIOPAddress(orb, hostname, templatePort);
IIOPProfileTemplate iiopProfile =
IIOPFactories.makeIIOPProfileTemplate(orb, version, addr);
if (version.supportsIORIIOPProfileComponents()) {
iiopProfile.add(IIOPFactories.makeCodeSetsComponent(orb));
iiopProfile.add(IIOPFactories.makeMaxStreamFormatVersionComponent());
RequestPartitioningPolicy rpPolicy = (RequestPartitioningPolicy)
policies.get_effective_policy(
ORBConstants.REQUEST_PARTITIONING_POLICY);
if (rpPolicy != null) {
iiopProfile.add(
IIOPFactories.makeRequestPartitioningComponent(
rpPolicy.getValue()));
}
if (codebase != null && codebase != "") {
iiopProfile.add(IIOPFactories. makeJavaCodebaseComponent(codebase));
}
if (orb.getORBData().isJavaSerializationEnabled()) {
iiopProfile.add(
IIOPFactories.makeJavaSerializationComponent());
}
}
iorTemplate.add(iiopProfile);
}
}
public String getMonitoringName()
{
return "AcceptedConnections";
}
////////////////////////////////////////////////////
//
// EventHandler methods
//
public SelectableChannel getChannel()
{
return serverSocketChannel;
}
public int getInterestOps()
{
return SelectionKey.OP_ACCEPT;
}
public Acceptor getAcceptor()
{
return this;
}
public Connection getConnection()
{
throw new RuntimeException("Should not happen.");
}
////////////////////////////////////////////////////
//
// Work methods.
//
/* CONFLICT: with legacy below.
public String getName()
{
return this.toString();
}
*/
public void doWork()
{
try {
if (orb.transportDebugFlag) {
dprint(".doWork->: " + this);
}
if (selectionKey.isAcceptable()) {
accept();
} else {
if (orb.transportDebugFlag) {
dprint(".doWork: ! selectionKey.isAcceptable: " + this);
}
}
} catch (SecurityException se) {
if (orb.transportDebugFlag) {
dprint(".doWork: ignoring SecurityException: "
+ se
+ " " + this);
}
String permissionStr = ORBUtility.getClassSecurityInfo(getClass());
wrapper.securityExceptionInAccept(se, permissionStr);
} catch (Exception ex) {
if (orb.transportDebugFlag) {
dprint(".doWork: ignoring Exception: "
+ ex
+ " " + this);
}
wrapper.exceptionInAccept(ex);
} catch (Throwable t) {
if (orb.transportDebugFlag) {
dprint(".doWork: ignoring Throwable: "
+ t
+ " " + this);
}
} finally {
// IMPORTANT: To avoid bug (4953599), we force the
// Thread that does the NIO select to also do the
// enable/disable of Ops using SelectionKey.interestOps().
// Otherwise, the SelectionKey.interestOps() may block
// indefinitely.
// NOTE: If "acceptorSocketUseWorkerThreadForEvent" is
// set to to false in ParserTable.java, then this method,
// doWork(), will get executed by the same thread
// (SelectorThread) that does the NIO select.
// If "acceptorSocketUseWorkerThreadForEvent" is set
// to true, a WorkerThread will execute this method,
// doWork(). Hence, the registering of the enabling of
// the SelectionKey's interestOps is done here instead
// of calling SelectionKey.interestOps(<interest op>).
Selector selector = orb.getTransportManager().getSelector(0);
if (selector != null) {
selector.registerInterestOps(this);
}
if (orb.transportDebugFlag) {
dprint(".doWork<-:" + this);
}
}
}
public void setEnqueueTime(long timeInMillis)
{
enqueueTime = timeInMillis;
}
public long getEnqueueTime()
{
return enqueueTime;
}
//
// Factory methods.
//
// REVISIT: refactor into common base or delegate.
public MessageMediator createMessageMediator(Broker broker,
Connection connection)
{
// REVISIT - no factoring so cheat to avoid code dup right now.
// REVISIT **** COUPLING !!!!
ContactInfo contactInfo = new SocketOrChannelContactInfoImpl();
return contactInfo.createMessageMediator(broker, connection);
}
// REVISIT: refactor into common base or delegate.
public MessageMediator finishCreatingMessageMediator(Broker broker,
Connection connection,
MessageMediator messageMediator)
{
// REVISIT - no factoring so cheat to avoid code dup right now.
// REVISIT **** COUPLING !!!!
ContactInfo contactInfo = new SocketOrChannelContactInfoImpl();
return contactInfo.finishCreatingMessageMediator(broker,
connection, messageMediator);
}
public InputObject createInputObject(Broker broker,
MessageMediator messageMediator)
{
CorbaMessageMediator corbaMessageMediator = (CorbaMessageMediator)
messageMediator;
return new CDRInputObject((ORB)broker,
(CorbaConnection)messageMediator.getConnection(),
corbaMessageMediator.getDispatchBuffer(),
corbaMessageMediator.getDispatchHeader());
}
public OutputObject createOutputObject(Broker broker,
MessageMediator messageMediator)
{
CorbaMessageMediator corbaMessageMediator = (CorbaMessageMediator)
messageMediator;
return sun.corba.OutputStreamFactory.newCDROutputObject((ORB) broker,
corbaMessageMediator, corbaMessageMediator.getReplyHeader(),
corbaMessageMediator.getStreamFormatVersion());
}
////////////////////////////////////////////////////
//
// SocketOrChannelAcceptor
//
public ServerSocket getServerSocket()
{
return serverSocket;
}
////////////////////////////////////////////////////
//
// Implementation.
//
public String toString()
{
String sock;
if (serverSocketChannel == null) {
if (serverSocket == null) {
sock = "(not initialized)";
} else {
sock = serverSocket.toString();
}
} else {
sock = serverSocketChannel.toString();
}
return
toStringName() +
"["
+ sock + " "
+ type + " "
+ shouldUseSelectThreadToWait() + " "
+ shouldUseWorkerThreadForEvent()
+ "]" ;
}
protected String toStringName()
{
return "SocketOrChannelAcceptorImpl";
}
protected void dprint(String msg)
{
ORBUtility.dprint(toStringName(), msg);
}
protected void dprint(String msg, Throwable t)
{
dprint(msg);
t.printStackTrace(System.out);
}
// BEGIN Legacy support
////////////////////////////////////////////////////
//
// LegacyServerSocketEndPointInfo and EndPointInfo
//
public String getType()
{
return type;
}
public String getHostName()
{
return hostname;
}
public String getHost()
{
return hostname;
}
public int getPort()
{
return port;
}
public int getLocatorPort()
{
return locatorPort;
}
public void setLocatorPort (int port)
{
locatorPort = port;
}
public String getName()
{
// Kluge alert:
// Work and Legacy both define getName.
// Try to make this behave best for most cases.
String result =
name.equals(LegacyServerSocketEndPointInfo.NO_NAME) ?
this.toString() : name;
return result;
}
// END Legacy support
}
// End of file.