1 /*
   2  * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.corba.se.impl.transport;
  27 
  28 import java.io.IOException;
  29 import java.net.InetSocketAddress;
  30 import java.net.ServerSocket;
  31 import java.net.Socket;
  32 import java.nio.channels.SelectableChannel;
  33 import java.nio.channels.SelectionKey;
  34 import java.nio.channels.ServerSocketChannel;
  35 import java.nio.channels.SocketChannel;
  36 import java.util.Iterator;
  37 
  38 import com.sun.corba.se.pept.broker.Broker;
  39 import com.sun.corba.se.pept.encoding.InputObject;
  40 import com.sun.corba.se.pept.encoding.OutputObject;
  41 import com.sun.corba.se.pept.protocol.MessageMediator;
  42 import com.sun.corba.se.pept.transport.Acceptor;
  43 import com.sun.corba.se.pept.transport.Connection;
  44 import com.sun.corba.se.pept.transport.ContactInfo;
  45 import com.sun.corba.se.pept.transport.EventHandler;
  46 import com.sun.corba.se.pept.transport.InboundConnectionCache;
  47 import com.sun.corba.se.pept.transport.Selector;
  48 
  49 import com.sun.corba.se.spi.extension.RequestPartitioningPolicy;
  50 import com.sun.corba.se.spi.ior.IORTemplate;
  51 import com.sun.corba.se.spi.ior.TaggedProfileTemplate;
  52 import com.sun.corba.se.spi.ior.iiop.IIOPAddress ;
  53 import com.sun.corba.se.spi.ior.iiop.IIOPFactories;
  54 import com.sun.corba.se.spi.ior.iiop.IIOPProfileTemplate ;
  55 import com.sun.corba.se.spi.ior.iiop.GIOPVersion ;
  56 import com.sun.corba.se.spi.ior.iiop.AlternateIIOPAddressComponent;
  57 import com.sun.corba.se.spi.logging.CORBALogDomains;
  58 import com.sun.corba.se.spi.orb.ORB;
  59 import com.sun.corba.se.spi.orbutil.threadpool.Work;
  60 import com.sun.corba.se.spi.protocol.CorbaMessageMediator;
  61 import com.sun.corba.se.spi.transport.CorbaAcceptor;
  62 import com.sun.corba.se.spi.transport.CorbaConnection;
  63 import com.sun.corba.se.spi.transport.SocketInfo;
  64 import com.sun.corba.se.spi.transport.SocketOrChannelAcceptor;
  65 
  66 import com.sun.corba.se.impl.encoding.CDRInputObject;
  67 import com.sun.corba.se.impl.encoding.CDROutputObject;
  68 import com.sun.corba.se.impl.logging.ORBUtilSystemException;
  69 import com.sun.corba.se.impl.oa.poa.Policies; // REVISIT impl/poa specific
  70 import com.sun.corba.se.impl.orbutil.ORBConstants;
  71 import com.sun.corba.se.impl.orbutil.ORBUtility;
  72 
  73 // BEGIN Legacy support.
  74 import com.sun.corba.se.spi.legacy.connection.LegacyServerSocketEndPointInfo;
  75 // END Legacy support.
  76 
  77 /**
  78  * @author Harold Carr
  79  */
  80 public class SocketOrChannelAcceptorImpl
  81     extends
  82         EventHandlerBase
  83     implements
  84         CorbaAcceptor,
  85         SocketOrChannelAcceptor,
  86         Work,
  87         // BEGIN Legacy
  88         SocketInfo,
  89         LegacyServerSocketEndPointInfo
  90         // END Legacy
  91 {
  92     protected ServerSocketChannel serverSocketChannel;
  93     protected ServerSocket serverSocket;
  94     protected int port;
  95     protected long enqueueTime;
  96     protected boolean initialized;
  97     protected ORBUtilSystemException wrapper ;
  98     protected InboundConnectionCache connectionCache;
  99 
 100     // BEGIN Legacy
 101     protected String type = "";
 102     protected String name = "";
 103     protected String hostname;
 104     protected int locatorPort;
 105     // END Legacy
 106 
 107     public SocketOrChannelAcceptorImpl(ORB orb)
 108     {
 109         this.orb = orb;
 110         wrapper = ORBUtilSystemException.get( orb,
 111             CORBALogDomains.RPC_TRANSPORT ) ;
 112 
 113         setWork(this);
 114         initialized = false;
 115 
 116         // BEGIN Legacy support.
 117         this.hostname = orb.getORBData().getORBServerHost();
 118         this.name = LegacyServerSocketEndPointInfo.NO_NAME;
 119         this.locatorPort = -1;
 120         // END Legacy support.
 121     }
 122 
 123     public SocketOrChannelAcceptorImpl(ORB orb, int port)
 124     {
 125         this(orb);
 126         this.port = port;
 127     }
 128 
 129     // BEGIN Legacy support.
 130     public SocketOrChannelAcceptorImpl(ORB orb, int port,
 131                                        String name, String type)
 132     {
 133         this(orb, port);
 134         this.name = name;
 135         this.type = type;
 136     }
 137     // END Legacy support.
 138 
 139     ////////////////////////////////////////////////////
 140     //
 141     // pept.transport.Acceptor
 142     //
 143 
 144     public boolean initialize()
 145     {
 146         if (initialized) {
 147             return false;
 148         }
 149         if (orb.transportDebugFlag) {
 150             dprint(".initialize: " + this);
 151         }
 152         InetSocketAddress inetSocketAddress = null;
 153         try {
 154             if (orb.getORBData().getListenOnAllInterfaces().equals(ORBConstants.LISTEN_ON_ALL_INTERFACES)) {
 155                 inetSocketAddress = new InetSocketAddress(port);
 156             } else {
 157                 String host = orb.getORBData().getORBServerHost();
 158                 inetSocketAddress = new InetSocketAddress(host, port);
 159             }
 160             serverSocket = orb.getORBData().getSocketFactory()
 161                 .createServerSocket(type, inetSocketAddress);
 162             internalInitialize();
 163         } catch (Throwable t) {
 164             throw wrapper.createListenerFailed( t, Integer.toString(port) ) ;
 165         }
 166         initialized = true;
 167         return true;
 168     }
 169 
 170     protected void internalInitialize()
 171         throws Exception
 172     {
 173         // Determine the listening port (for the IOR).
 174         // This is important when using emphemeral ports (i.e.,
 175         // when the port value to the constructor is 0).
 176 
 177         port = serverSocket.getLocalPort();
 178 
 179         // Register with transport (also sets up monitoring).
 180 
 181         orb.getCorbaTransportManager().getInboundConnectionCache(this);
 182 
 183         // Finish configuation.
 184 
 185         serverSocketChannel = serverSocket.getChannel();
 186 
 187         if (serverSocketChannel != null) {
 188             setUseSelectThreadToWait(
 189                 orb.getORBData().acceptorSocketUseSelectThreadToWait());
 190             serverSocketChannel.configureBlocking(
 191                 ! orb.getORBData().acceptorSocketUseSelectThreadToWait());
 192         } else {
 193             // Configure to use listener and reader threads.
 194             setUseSelectThreadToWait(false);
 195         }
 196         setUseWorkerThreadForEvent(
 197             orb.getORBData().acceptorSocketUseWorkerThreadForEvent());
 198 
 199     }
 200 
 201     public boolean initialized()
 202     {
 203         return initialized;
 204     }
 205 
 206     public String getConnectionCacheType()
 207     {
 208         return this.getClass().toString();
 209     }
 210 
 211     public void setConnectionCache(InboundConnectionCache connectionCache)
 212     {
 213         this.connectionCache = connectionCache;
 214     }
 215 
 216     public InboundConnectionCache getConnectionCache()
 217     {
 218         return connectionCache;
 219     }
 220 
 221     public boolean shouldRegisterAcceptEvent()
 222     {
 223         return true;
 224     }
 225 
 226     public void accept()
 227     {
 228         try {
 229             SocketChannel socketChannel = null;
 230             Socket socket = null;
 231             if (serverSocketChannel == null) {
 232                 socket = serverSocket.accept();
 233             } else {
 234                 socketChannel = serverSocketChannel.accept();
 235                 socket = socketChannel.socket();
 236             }
 237             orb.getORBData().getSocketFactory()
 238                 .setAcceptedSocketOptions(this, serverSocket, socket);
 239             if (orb.transportDebugFlag) {
 240                 dprint(".accept: " +
 241                        (serverSocketChannel == null
 242                         ? serverSocket.toString()
 243                         : serverSocketChannel.toString()));
 244             }
 245 
 246             CorbaConnection connection =
 247                 new SocketOrChannelConnectionImpl(orb, this, socket);
 248             if (orb.transportDebugFlag) {
 249                 dprint(".accept: new: " + connection);
 250             }
 251 
 252             // NOTE: The connection MUST be put in the cache BEFORE being
 253             // registered with the selector.  Otherwise if the bytes
 254             // are read on the connection it will attempt a time stamp
 255             // but the cache will be null, resulting in NPE.
 256 
 257             // A connection needs to be timestamped before putting to the cache.
 258             // Otherwise the newly created connection (with 0 timestamp) could be
 259             // incorrectly reclaimed by concurrent reclaim() call OR if there
 260             // will be no events on this connection then it could be reclaimed
 261             // by upcoming reclaim() call.
 262             getConnectionCache().stampTime(connection);
 263             getConnectionCache().put(this, connection);
 264 
 265             if (connection.shouldRegisterServerReadEvent()) {
 266                 Selector selector = orb.getTransportManager().getSelector(0);
 267                 if (selector != null) {
 268                     if (orb.transportDebugFlag) {
 269                         dprint(".accept: registerForEvent: " + connection);
 270                     }
 271                     selector.registerForEvent(connection.getEventHandler());
 272                 }
 273             }
 274 
 275             getConnectionCache().reclaim();
 276 
 277         } catch (IOException e) {
 278             if (orb.transportDebugFlag) {
 279                 dprint(".accept:", e);
 280             }
 281             Selector selector = orb.getTransportManager().getSelector(0);
 282             if (selector != null) {
 283                 selector.unregisterForEvent(this);
 284                 // REVISIT - need to close - recreate - then register new one.
 285                 selector.registerForEvent(this);
 286                 // NOTE: if register cycling we do not want to shut down ORB
 287                 // since local beans will still work.  Instead one will see
 288                 // a growing log file to alert admin of problem.
 289             }
 290         }
 291     }
 292 
 293     public void close ()
 294     {
 295         try {
 296             if (orb.transportDebugFlag) {
 297                 dprint(".close->:");
 298             }
 299             Selector selector = orb.getTransportManager().getSelector(0);
 300             if (selector != null) {
 301                 selector.unregisterForEvent(this);
 302             }
 303             if (serverSocketChannel != null) {
 304                 serverSocketChannel.close();
 305             }
 306             if (serverSocket != null) {
 307                 serverSocket.close();
 308             }
 309         } catch (IOException e) {
 310             if (orb.transportDebugFlag) {
 311                 dprint(".close:", e);
 312             }
 313         } finally {
 314             if (orb.transportDebugFlag) {
 315                 dprint(".close<-:");
 316             }
 317         }
 318     }
 319 
 320     public EventHandler getEventHandler()
 321     {
 322         return this;
 323     }
 324 
 325     ////////////////////////////////////////////////////
 326     //
 327     // CorbaAcceptor
 328     //
 329 
 330     public String getObjectAdapterId()
 331     {
 332         return null;
 333     }
 334 
 335     public String getObjectAdapterManagerId()
 336     {
 337         return null;
 338     }
 339 
 340     public void addToIORTemplate(IORTemplate iorTemplate,
 341                                  Policies policies,
 342                                  String codebase)
 343     {
 344         Iterator iterator = iorTemplate.iteratorById(
 345             org.omg.IOP.TAG_INTERNET_IOP.value);
 346 
 347         String hostname = orb.getORBData().getORBServerHost();
 348 
 349         if (iterator.hasNext()) {
 350             // REVISIT - how does this play with legacy ORBD port exchange?
 351             IIOPAddress iiopAddress =
 352                 IIOPFactories.makeIIOPAddress(orb, hostname, port);
 353             AlternateIIOPAddressComponent iiopAddressComponent =
 354                 IIOPFactories.makeAlternateIIOPAddressComponent(iiopAddress);
 355 
 356             while (iterator.hasNext()) {
 357                 TaggedProfileTemplate taggedProfileTemplate =
 358                     (TaggedProfileTemplate) iterator.next();
 359                 taggedProfileTemplate.add(iiopAddressComponent);
 360             }
 361         } else {
 362             GIOPVersion version = orb.getORBData().getGIOPVersion();
 363             int templatePort;
 364             if (policies.forceZeroPort()) {
 365                 templatePort = 0;
 366             } else if (policies.isTransient()) {
 367                 templatePort = port;
 368             } else {
 369                 templatePort = orb.getLegacyServerSocketManager()
 370                    .legacyGetPersistentServerPort(SocketInfo.IIOP_CLEAR_TEXT);
 371             }
 372             IIOPAddress addr =
 373                 IIOPFactories.makeIIOPAddress(orb, hostname, templatePort);
 374             IIOPProfileTemplate iiopProfile =
 375                 IIOPFactories.makeIIOPProfileTemplate(orb, version, addr);
 376             if (version.supportsIORIIOPProfileComponents()) {
 377                 iiopProfile.add(IIOPFactories.makeCodeSetsComponent(orb));
 378                 iiopProfile.add(IIOPFactories.makeMaxStreamFormatVersionComponent());
 379                 RequestPartitioningPolicy rpPolicy = (RequestPartitioningPolicy)
 380                     policies.get_effective_policy(
 381                                       ORBConstants.REQUEST_PARTITIONING_POLICY);
 382                 if (rpPolicy != null) {
 383                     iiopProfile.add(
 384                          IIOPFactories.makeRequestPartitioningComponent(
 385                              rpPolicy.getValue()));
 386                 }
 387                 if (codebase != null && codebase != "") {
 388                     iiopProfile.add(IIOPFactories. makeJavaCodebaseComponent(codebase));
 389                 }
 390                 if (orb.getORBData().isJavaSerializationEnabled()) {
 391                     iiopProfile.add(
 392                            IIOPFactories.makeJavaSerializationComponent());
 393                 }
 394             }
 395             iorTemplate.add(iiopProfile);
 396         }
 397     }
 398 
 399     public String getMonitoringName()
 400     {
 401         return "AcceptedConnections";
 402     }
 403 
 404     ////////////////////////////////////////////////////
 405     //
 406     // EventHandler methods
 407     //
 408 
 409     public SelectableChannel getChannel()
 410     {
 411         return serverSocketChannel;
 412     }
 413 
 414     public int getInterestOps()
 415     {
 416         return SelectionKey.OP_ACCEPT;
 417     }
 418 
 419     public Acceptor getAcceptor()
 420     {
 421         return this;
 422     }
 423 
 424     public Connection getConnection()
 425     {
 426         throw new RuntimeException("Should not happen.");
 427     }
 428 
 429     ////////////////////////////////////////////////////
 430     //
 431     // Work methods.
 432     //
 433 
 434     /* CONFLICT: with legacy below.
 435     public String getName()
 436     {
 437         return this.toString();
 438     }
 439     */
 440 
 441     public void doWork()
 442     {
 443         try {
 444             if (orb.transportDebugFlag) {
 445                 dprint(".doWork->: " + this);
 446             }
 447             if (selectionKey.isAcceptable()) {
 448                         accept();
 449             } else {
 450                 if (orb.transportDebugFlag) {
 451                     dprint(".doWork: ! selectionKey.isAcceptable: " + this);
 452                 }
 453             }
 454         } catch (SecurityException se) {
 455             if (orb.transportDebugFlag) {
 456                 dprint(".doWork: ignoring SecurityException: "
 457                        + se
 458                        + " " + this);
 459             }
 460             String permissionStr = ORBUtility.getClassSecurityInfo(getClass());
 461             wrapper.securityExceptionInAccept(se, permissionStr);
 462         } catch (Exception ex) {
 463             if (orb.transportDebugFlag) {
 464                 dprint(".doWork: ignoring Exception: "
 465                        + ex
 466                        + " " + this);
 467             }
 468             wrapper.exceptionInAccept(ex);
 469         } catch (Throwable t) {
 470             if (orb.transportDebugFlag) {
 471                 dprint(".doWork: ignoring Throwable: "
 472                        + t
 473                        + " " + this);
 474             }
 475         } finally {
 476 
 477             // IMPORTANT: To avoid bug (4953599), we force the
 478             // Thread that does the NIO select to also do the
 479             // enable/disable of Ops using SelectionKey.interestOps().
 480             // Otherwise, the SelectionKey.interestOps() may block
 481             // indefinitely.
 482             // NOTE: If "acceptorSocketUseWorkerThreadForEvent" is
 483             // set to to false in ParserTable.java, then this method,
 484             // doWork(), will get executed by the same thread
 485             // (SelectorThread) that does the NIO select.
 486             // If "acceptorSocketUseWorkerThreadForEvent" is set
 487             // to true, a WorkerThread will execute this method,
 488             // doWork(). Hence, the registering of the enabling of
 489             // the SelectionKey's interestOps is done here instead
 490             // of calling SelectionKey.interestOps(<interest op>).
 491 
 492             Selector selector = orb.getTransportManager().getSelector(0);
 493             if (selector != null) {
 494                 selector.registerInterestOps(this);
 495             }
 496 
 497             if (orb.transportDebugFlag) {
 498                 dprint(".doWork<-:" + this);
 499             }
 500         }
 501     }
 502 
 503     public void setEnqueueTime(long timeInMillis)
 504     {
 505         enqueueTime = timeInMillis;
 506     }
 507 
 508     public long getEnqueueTime()
 509     {
 510         return enqueueTime;
 511     }
 512 
 513 
 514     //
 515     // Factory methods.
 516     //
 517 
 518     // REVISIT: refactor into common base or delegate.
 519     public MessageMediator createMessageMediator(Broker broker,
 520                                                  Connection connection)
 521     {
 522         // REVISIT - no factoring so cheat to avoid code dup right now.
 523         // REVISIT **** COUPLING !!!!
 524         ContactInfo contactInfo = new SocketOrChannelContactInfoImpl();
 525         return contactInfo.createMessageMediator(broker, connection);
 526     }
 527 
 528     // REVISIT: refactor into common base or delegate.
 529     public MessageMediator finishCreatingMessageMediator(Broker broker,
 530                                                          Connection connection,
 531                                                          MessageMediator messageMediator)
 532     {
 533         // REVISIT - no factoring so cheat to avoid code dup right now.
 534         // REVISIT **** COUPLING !!!!
 535         ContactInfo contactInfo = new SocketOrChannelContactInfoImpl();
 536         return contactInfo.finishCreatingMessageMediator(broker,
 537                                           connection, messageMediator);
 538     }
 539 
 540     public InputObject createInputObject(Broker broker,
 541                                          MessageMediator messageMediator)
 542     {
 543         CorbaMessageMediator corbaMessageMediator = (CorbaMessageMediator)
 544             messageMediator;
 545         return new CDRInputObject((ORB)broker,
 546                                   (CorbaConnection)messageMediator.getConnection(),
 547                                   corbaMessageMediator.getDispatchBuffer(),
 548                                   corbaMessageMediator.getDispatchHeader());
 549     }
 550 
 551     public OutputObject createOutputObject(Broker broker,
 552                                            MessageMediator messageMediator)
 553     {
 554         CorbaMessageMediator corbaMessageMediator = (CorbaMessageMediator)
 555             messageMediator;
 556         return sun.corba.OutputStreamFactory.newCDROutputObject((ORB) broker,
 557                        corbaMessageMediator, corbaMessageMediator.getReplyHeader(),
 558                        corbaMessageMediator.getStreamFormatVersion());
 559     }
 560 
 561     ////////////////////////////////////////////////////
 562     //
 563     // SocketOrChannelAcceptor
 564     //
 565 
 566     public ServerSocket getServerSocket()
 567     {
 568         return serverSocket;
 569     }
 570 
 571     ////////////////////////////////////////////////////
 572     //
 573     // Implementation.
 574     //
 575 
 576     public String toString()
 577     {
 578         String sock;
 579         if (serverSocketChannel == null) {
 580             if (serverSocket == null) {
 581                 sock = "(not initialized)";
 582             } else {
 583                 sock = serverSocket.toString();
 584             }
 585         } else {
 586             sock = serverSocketChannel.toString();
 587         }
 588 
 589         return
 590             toStringName() +
 591             "["
 592             + sock + " "
 593             + type + " "
 594             + shouldUseSelectThreadToWait() + " "
 595             + shouldUseWorkerThreadForEvent()
 596             + "]" ;
 597     }
 598 
 599     protected String toStringName()
 600     {
 601         return "SocketOrChannelAcceptorImpl";
 602     }
 603 
 604     protected void dprint(String msg)
 605     {
 606         ORBUtility.dprint(toStringName(), msg);
 607     }
 608 
 609     protected void dprint(String msg, Throwable t)
 610     {
 611         dprint(msg);
 612         t.printStackTrace(System.out);
 613     }
 614 
 615     // BEGIN Legacy support
 616     ////////////////////////////////////////////////////
 617     //
 618     // LegacyServerSocketEndPointInfo and EndPointInfo
 619     //
 620 
 621     public String getType()
 622     {
 623         return type;
 624     }
 625 
 626     public String getHostName()
 627     {
 628         return hostname;
 629     }
 630 
 631     public String getHost()
 632     {
 633         return hostname;
 634     }
 635 
 636     public int getPort()
 637     {
 638         return port;
 639     }
 640 
 641     public int getLocatorPort()
 642     {
 643         return locatorPort;
 644     }
 645 
 646     public void setLocatorPort (int port)
 647     {
 648         locatorPort = port;
 649     }
 650 
 651     public String getName()
 652     {
 653         // Kluge alert:
 654         // Work and Legacy both define getName.
 655         // Try to make this behave best for most cases.
 656         String result =
 657             name.equals(LegacyServerSocketEndPointInfo.NO_NAME) ?
 658             this.toString() : name;
 659         return result;
 660     }
 661     // END Legacy support
 662 }
 663 
 664 // End of file.