Example #1
0
  public static ChannelServer create(final Configuration configuration) throws IOException {
    if (configuration == null) {
      throw new IllegalArgumentException("Null configuration");
    }
    configuration.validate();

    final Endpoint endpoint =
        Remoting.createEndpoint(configuration.getEndpointName(), configuration.getOptionMap());

    Registration registration =
        endpoint.addConnectionProvider(
            configuration.getUriScheme(),
            new RemoteConnectionProviderFactory(),
            OptionMap.create(Options.SSL_ENABLED, Boolean.FALSE));

    final NetworkServerProvider networkServerProvider =
        endpoint.getConnectionProviderInterface(
            configuration.getUriScheme(), NetworkServerProvider.class);
    SimpleServerAuthenticationProvider provider = new SimpleServerAuthenticationProvider();
    // There is currently a probable bug in jboss remoting, so the user realm name MUST be the same
    // as
    // the endpoint name.
    provider.addUser("bob", configuration.getEndpointName(), "pass".toCharArray());
    AcceptingChannel<? extends ConnectedStreamChannel> streamServer =
        networkServerProvider.createServer(
            configuration.getBindAddress(),
            OptionMap.create(Options.SASL_MECHANISMS, Sequence.of("CRAM-MD5")),
            provider,
            null);

    return new ChannelServer(endpoint, registration, streamServer);
  }
Example #2
0
 /**
  * Create a new client mode SSL engine, configured from an option map.
  *
  * @param sslContext the SSL context
  * @param optionMap the SSL options
  * @param peerAddress the peer address of the connection
  * @return the configured SSL engine
  */
 public static SSLEngine createSSLEngine(
     SSLContext sslContext, OptionMap optionMap, InetSocketAddress peerAddress) {
   final SSLEngine engine =
       sslContext.createSSLEngine(
           optionMap.get(Options.SSL_PEER_HOST_NAME, getHostNameNoResolve(peerAddress)),
           optionMap.get(Options.SSL_PEER_PORT, peerAddress.getPort()));
   engine.setUseClientMode(true);
   engine.setEnableSessionCreation(optionMap.get(Options.SSL_ENABLE_SESSION_CREATION, true));
   final Sequence<String> cipherSuites = optionMap.get(Options.SSL_ENABLED_CIPHER_SUITES);
   if (cipherSuites != null) {
     final Set<String> supported =
         new HashSet<String>(Arrays.asList(engine.getSupportedCipherSuites()));
     final List<String> finalList = new ArrayList<String>();
     for (String name : cipherSuites) {
       if (supported.contains(name)) {
         finalList.add(name);
       }
     }
     engine.setEnabledCipherSuites(finalList.toArray(new String[finalList.size()]));
   }
   final Sequence<String> protocols = optionMap.get(Options.SSL_ENABLED_PROTOCOLS);
   if (protocols != null) {
     final Set<String> supported =
         new HashSet<String>(Arrays.asList(engine.getSupportedProtocols()));
     final List<String> finalList = new ArrayList<String>();
     for (String name : protocols) {
       if (supported.contains(name)) {
         finalList.add(name);
       }
     }
     engine.setEnabledProtocols(finalList.toArray(new String[finalList.size()]));
   }
   return engine;
 }
  public void start() {
    final Xnio xnio;
    try {
      // Do what org.jboss.as.remoting.XnioUtil does
      xnio =
          Xnio.getInstance(
              null,
              Module.getModuleFromCallerModuleLoader(
                      ModuleIdentifier.fromString("org.jboss.xnio.nio"))
                  .getClassLoader());
    } catch (Exception e) {
      throw new IllegalStateException(e.getLocalizedMessage());
    }
    try {
      // TODO make this configurable
      worker =
          xnio.createWorker(
              OptionMap.builder()
                  .set(Options.WORKER_IO_THREADS, 4)
                  .set(Options.CONNECTION_HIGH_WATER, 1000000)
                  .set(Options.CONNECTION_LOW_WATER, 1000000)
                  .set(Options.WORKER_TASK_CORE_THREADS, 10)
                  .set(Options.WORKER_TASK_MAX_THREADS, 12)
                  .set(Options.TCP_NODELAY, true)
                  .set(Options.CORK, true)
                  .getMap());

      Builder serverOptionsBuilder =
          OptionMap.builder().set(Options.TCP_NODELAY, true).set(Options.REUSE_ADDRESSES, true);
      ChannelListener acceptListener = ChannelListeners.openListenerAdapter(openListener);
      if (httpAddress != null) {
        normalServer =
            worker.createStreamConnectionServer(
                httpAddress, acceptListener, serverOptionsBuilder.getMap());
        normalServer.resumeAccepts();
      }
      if (secureAddress != null) {
        SSLContext sslContext = securityRealm.getSSLContext();
        Set<AuthMechanism> supportedMechanisms =
            securityRealm.getSupportedAuthenticationMechanisms();
        if (supportedMechanisms.contains(AuthMechanism.CLIENT_CERT)) {
          if (supportedMechanisms.contains(AuthMechanism.DIGEST)
              || supportedMechanisms.contains(AuthMechanism.PLAIN)) {
            // Username / Password auth is possible so don't mandate a client certificate.
            serverOptionsBuilder.set(SSL_CLIENT_AUTH_MODE, REQUESTED);
          } else {
            serverOptionsBuilder.set(SSL_CLIENT_AUTH_MODE, REQUIRED);
          }
        }
        OptionMap secureOptions = serverOptionsBuilder.getMap();
        XnioSsl xnioSsl = new JsseXnioSsl(worker.getXnio(), secureOptions, sslContext);
        secureServer =
            xnioSsl.createSslConnectionServer(worker, secureAddress, acceptListener, secureOptions);
        secureServer.resumeAccepts();
      }
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }
    @Override
    protected void addExtraServices(ServiceTarget target) {
      super.addExtraServices(target);
      target
          .addService(Services.JBOSS_SERVICE_MODULE_LOADER, new ServiceModuleLoader(null))
          .install();
      target
          .addService(ContextNames.JAVA_CONTEXT_SERVICE_NAME, new NamingStoreService())
          .setInitialMode(ServiceController.Mode.ACTIVE)
          .install();
      target
          .addService(ContextNames.JBOSS_CONTEXT_SERVICE_NAME, new NamingStoreService())
          .setInitialMode(ServiceController.Mode.ACTIVE)
          .install();

      target
          .addService(
              IOServices.WORKER.append("default"),
              new WorkerService(OptionMap.builder().set(Options.WORKER_IO_THREADS, 2).getMap()))
          .setInitialMode(ServiceController.Mode.ACTIVE)
          .install();

      target
          .addService(
              IOServices.WORKER.append("non-default"),
              new WorkerService(OptionMap.builder().set(Options.WORKER_IO_THREADS, 2).getMap()))
          .setInitialMode(ServiceController.Mode.ACTIVE)
          .install();

      target
          .addService(
              IOServices.BUFFER_POOL.append("default"), new BufferPoolService(2048, 2048, true))
          .setInitialMode(ServiceController.Mode.ACTIVE)
          .install();
      // ListenerRegistry.Listener listener = new ListenerRegistry.Listener("http", "default",
      // "default",
      // InetSocketAddress.createUnresolved("localhost",8080));
      target
          .addService(HttpListenerAdd.REGISTRY_SERVICE_NAME, new HttpListenerRegistryService())
          .setInitialMode(ServiceController.Mode.ACTIVE)
          .install();

      target
          .addService(
              SecurityRealm.ServiceUtil.createServiceName("UndertowRealm"),
              new SecurityRealmService("UndertowRealm", false))
          .setInitialMode(ServiceController.Mode.ACTIVE)
          .install();
      target
          .addService(
              SecurityRealm.ServiceUtil.createServiceName("other"),
              new SecurityRealmService("other", false))
          .setInitialMode(ServiceController.Mode.ACTIVE)
          .install();
    }
  public void start() {
    final Xnio xnio;
    try {
      // Do what org.jboss.as.remoting.XnioUtil does
      xnio =
          Xnio.getInstance(
              null,
              Module.getModuleFromCallerModuleLoader(
                      ModuleIdentifier.fromString("org.jboss.xnio.nio"))
                  .getClassLoader());
    } catch (Exception e) {
      throw new IllegalStateException(e.getLocalizedMessage());
    }
    try {
      // TODO make this configurable
      worker =
          xnio.createWorker(
              OptionMap.builder()
                  .set(Options.WORKER_IO_THREADS, 2)
                  .set(Options.WORKER_TASK_CORE_THREADS, 5)
                  .set(Options.WORKER_TASK_MAX_THREADS, 10)
                  .set(Options.TCP_NODELAY, true)
                  .set(Options.CORK, true)
                  .getMap());

      Builder serverOptionsBuilder =
          OptionMap.builder().set(Options.TCP_NODELAY, true).set(Options.REUSE_ADDRESSES, true);
      ChannelListener acceptListener = ChannelListeners.openListenerAdapter(openListener);
      if (httpAddress != null) {
        normalServer =
            worker.createStreamConnectionServer(
                httpAddress, acceptListener, serverOptionsBuilder.getMap());
        normalServer.resumeAccepts();
      }
      if (secureAddress != null) {
        if (sslClientAuthMode != null) {
          serverOptionsBuilder.set(SSL_CLIENT_AUTH_MODE, sslClientAuthMode);
        }
        OptionMap secureOptions = serverOptionsBuilder.getMap();
        XnioSsl xnioSsl = new UndertowXnioSsl(worker.getXnio(), secureOptions, sslContext);
        secureServer =
            xnioSsl.createSslConnectionServer(worker, secureAddress, acceptListener, secureOptions);
        secureServer.resumeAccepts();
      }
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }
  // This duplicates the RealmSecurityProvider of AS7 to mimic the same security set-up
  private OptionMap createOptionMap() {
    List<String> mechanisms = new LinkedList<String>();
    Set<Property> properties = new HashSet<Property>();
    Builder builder = OptionMap.builder();

    if (saslMechanisms.contains(JBOSS_LOCAL_USER)) {
      mechanisms.add(JBOSS_LOCAL_USER);
      builder.set(SASL_POLICY_NOPLAINTEXT, false);
      properties.add(Property.of(LOCAL_DEFAULT_USER, DOLLAR_LOCAL));
    }

    if (saslMechanisms.contains(DIGEST_MD5)) {
      mechanisms.add(DIGEST_MD5);
      properties.add(Property.of(REALM_PROPERTY, REALM));
    }

    if (saslMechanisms.contains(PLAIN)) {
      mechanisms.add(PLAIN);
      builder.set(SASL_POLICY_NOPLAINTEXT, false);
    }

    if (saslMechanisms.isEmpty() || saslMechanisms.contains(ANONYMOUS)) {
      mechanisms.add(ANONYMOUS);
      builder.set(SASL_POLICY_NOANONYMOUS, false);
    }

    // TODO - SSL Options will be added in a subsequent task.
    builder.set(SSL_ENABLED, false);

    builder.set(SASL_MECHANISMS, Sequence.of(mechanisms));
    builder.set(SASL_PROPERTIES, Sequence.of(properties));

    return builder.getMap();
  }
  public IoFuture<Connection> connect(
      CallbackHandler handler, Map<String, String> saslOptions, SSLContext sslContext)
      throws IOException {
    OptionMap.Builder builder = OptionMap.builder();
    builder.addAll(configuration.getOptionMap());
    builder.set(SASL_POLICY_NOANONYMOUS, Boolean.FALSE);
    builder.set(SASL_POLICY_NOPLAINTEXT, Boolean.FALSE);
    if (isLocal() == false) {
      builder.set(Options.SASL_DISALLOWED_MECHANISMS, Sequence.of(JBOSS_LOCAL_USER));
    }
    List<Property> tempProperties =
        new ArrayList<Property>(saslOptions != null ? saslOptions.size() : 1);
    tempProperties.add(Property.of("jboss.sasl.local-user.quiet-auth", "true"));
    if (saslOptions != null) {
      for (String currentKey : saslOptions.keySet()) {
        tempProperties.add(Property.of(currentKey, saslOptions.get(currentKey)));
      }
    }
    builder.set(Options.SASL_PROPERTIES, Sequence.of(tempProperties));

    builder.set(Options.SSL_ENABLED, true);
    builder.set(Options.SSL_STARTTLS, true);

    CallbackHandler actualHandler = handler != null ? handler : new AnonymousCallbackHandler();
    return endpoint.connect(uri, builder.getMap(), actualHandler, sslContext);
  }
  static {
    final BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<Runnable>();
    final ThreadFactory threadFactory =
        new JBossThreadFactory(
            new ThreadGroup("cli-remoting"),
            Boolean.FALSE,
            null,
            "%G - %t",
            null,
            null,
            doPrivileged(GetAccessControlContextAction.getInstance()));
    executorService = new ThreadPoolExecutor(2, 4, 60L, TimeUnit.SECONDS, workQueue, threadFactory);
    // Allow the core threads to time out as well
    executorService.allowCoreThreadTimeOut(true);

    try {
      endpoint = Remoting.createEndpoint("cli-client", OptionMap.EMPTY);
      endpoint.addConnectionProvider(
          "remote", new RemoteConnectionProviderFactory(), OptionMap.EMPTY);
      endpoint.addConnectionProvider(
          "http-remoting",
          new HttpUpgradeConnectionProviderFactory(),
          OptionMap.create(Options.SSL_ENABLED, Boolean.FALSE));
      endpoint.addConnectionProvider(
          "https-remoting",
          new HttpUpgradeConnectionProviderFactory(),
          OptionMap.create(Options.SSL_ENABLED, Boolean.TRUE));
    } catch (IOException e) {
      throw new IllegalStateException("Failed to create remoting endpoint", e);
    }

    CliShutdownHook.add(
        new CliShutdownHook.Handler() {
          @Override
          public void shutdown() {
            executorService.shutdown();
            try {
              executorService.awaitTermination(1, TimeUnit.SECONDS);
            } catch (InterruptedException e) {
            }
            try {
              endpoint.close();
            } catch (IOException e) {
            }
          }
        });
  }
 ClientConnectionOpenListener(
     final RemoteConnection connection,
     final CallbackHandler callbackHandler,
     final AccessControlContext accessControlContext,
     final OptionMap optionMap) {
   this.connection = connection;
   this.callbackHandler = callbackHandler;
   this.accessControlContext = accessControlContext;
   this.optionMap = optionMap;
   final Sequence<String> allowedMechs = optionMap.get(Options.SASL_MECHANISMS);
   final Sequence<String> disallowedMechs = optionMap.get(Options.SASL_DISALLOWED_MECHANISMS);
   this.allowedMechs = allowedMechs == null ? null : new HashSet<String>(allowedMechs);
   this.disallowedMechs =
       disallowedMechs == null
           ? Collections.<String>emptySet()
           : new HashSet<String>(disallowedMechs);
 }
  @Override
  public void handleEvent(StreamConnection channel) {
    // set read and write timeouts
    try {
      Integer readTimeout = channel.getOption(Options.READ_TIMEOUT);
      Integer idleTimeout = undertowOptions.get(UndertowOptions.IDLE_TIMEOUT);
      if ((readTimeout == null || readTimeout <= 0) && idleTimeout != null) {
        readTimeout = idleTimeout;
      } else if (readTimeout != null && idleTimeout != null && idleTimeout > 0) {
        readTimeout = Math.min(readTimeout, idleTimeout);
      }
      if (readTimeout != null && readTimeout > 0) {
        channel
            .getSourceChannel()
            .setConduit(
                new ReadTimeoutStreamSourceConduit(
                    channel.getSourceChannel().getConduit(), channel, this));
      }
      Integer writeTimeout = channel.getOption(Options.WRITE_TIMEOUT);
      if ((writeTimeout == null || writeTimeout <= 0) && idleTimeout != null) {
        writeTimeout = idleTimeout;
      } else if (writeTimeout != null && idleTimeout != null && idleTimeout > 0) {
        writeTimeout = Math.min(writeTimeout, idleTimeout);
      }
      if (writeTimeout != null && writeTimeout > 0) {
        channel
            .getSinkChannel()
            .setConduit(
                new WriteTimeoutStreamSinkConduit(
                    channel.getSinkChannel().getConduit(), channel, this));
      }
    } catch (IOException e) {
      IoUtils.safeClose(channel);
      UndertowLogger.REQUEST_IO_LOGGER.ioException(e);
    }

    final PortForwardServerConnection connection =
        new PortForwardServerConnection(channel, bufferPool, undertowOptions, bufferSize);
    connection
        .getWorker()
        .execute(
            new Runnable() {
              @Override
              public void run() {
                try {
                  connection.startForwarding(
                      masterPortForwardConnection,
                      urlPath,
                      targetPort,
                      requestId.getAndIncrement());
                } catch (IOException e) {
                } finally {
                  IoUtils.safeClose(connection);
                }
              }
            });
  }
  public static OptionMap populate(final ExpressionResolver resolver, final ModelNode model)
      throws OperationFailedException {
    OptionMap.Builder builder =
        OptionMap.builder()
            .set(Options.TCP_NODELAY, Boolean.TRUE)
            .set(Options.REUSE_ADDRESSES, true)
            .addAll(OptionList.resolveOptions(resolver, model, RemotingEndpointResource.OPTIONS));

    return builder.getMap();
  }
  /**
   * Create and setup the remoting connection
   *
   * @throws Exception
   */
  @BeforeClass
  public static void beforeTestClass() throws Exception {
    final Endpoint endpoint =
        Remoting.createEndpoint("ejb-remote-client-endpoint", OptionMap.EMPTY);
    endpoint.addConnectionProvider(
        "remote",
        new RemoteConnectionProviderFactory(),
        OptionMap.create(Options.SSL_ENABLED, Boolean.FALSE));

    // open a connection
    final int ejbRemotingPort =
        EJBRemoteManagementUtil.getEJBRemoteConnectorPort("localhost", 9999);
    final IoFuture<Connection> futureConnection =
        endpoint.connect(
            new URI("remote://localhost:" + ejbRemotingPort),
            OptionMap.create(Options.SASL_POLICY_NOANONYMOUS, Boolean.FALSE),
            new AnonymousCallbackHandler());
    connection = IoFutureHelper.get(futureConnection, 5, TimeUnit.SECONDS);
  }
 ClientConnectionOpenListener(
     final URI uri,
     final RemoteConnection connection,
     final ConnectionProviderContext connectionProviderContext,
     final AuthenticationContext authenticationContext,
     final SaslClientFactory saslClientFactory,
     final OptionMap optionMap) {
   this.uri = uri;
   this.connection = connection;
   this.connectionProviderContext = connectionProviderContext;
   this.authenticationContext = authenticationContext;
   this.saslClientFactory = saslClientFactory;
   this.optionMap = optionMap;
   final Sequence<String> allowedMechs = optionMap.get(Options.SASL_MECHANISMS);
   final Sequence<String> disallowedMechs = optionMap.get(Options.SASL_DISALLOWED_MECHANISMS);
   this.allowedMechs = allowedMechs == null ? null : new HashSet<String>(allowedMechs);
   this.disallowedMechs =
       disallowedMechs == null
           ? Collections.<String>emptySet()
           : new HashSet<String>(disallowedMechs);
 }
Example #14
0
 /**
  * Create a new SSL context, configured from an option map and the given parameters.
  *
  * @param keyManagers the key managers to use, or {@code null} to configure from the option map
  * @param trustManagers the trust managers to use, or {@code null} to configure from the option
  *     map
  * @param secureRandom the secure RNG to use, or {@code null} to choose a system default
  * @param optionMap the SSL context options
  * @return a new context
  * @throws NoSuchProviderException if there is no matching provider
  * @throws NoSuchAlgorithmException if there is no matching algorithm
  * @throws KeyManagementException if the context initialization fails
  */
 public static SSLContext createSSLContext(
     KeyManager[] keyManagers,
     TrustManager[] trustManagers,
     SecureRandom secureRandom,
     OptionMap optionMap)
     throws NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException {
   final String provider = optionMap.get(Options.SSL_PROVIDER);
   final String protocol = optionMap.get(Options.SSL_PROTOCOL);
   final SSLContext sslContext;
   if (protocol == null) {
     // Default context is initialized automatically
     return SSLContext.getDefault();
   } else if (provider == null) {
     sslContext = SSLContext.getInstance(protocol);
   } else {
     sslContext = SSLContext.getInstance(protocol, provider);
   }
   if (keyManagers == null) {
     final Sequence<Class<? extends KeyManager>> keyManagerClasses =
         optionMap.get(Options.SSL_JSSE_KEY_MANAGER_CLASSES);
     if (keyManagerClasses != null) {
       final int size = keyManagerClasses.size();
       keyManagers = new KeyManager[size];
       for (int i = 0; i < size; i++) {
         keyManagers[i] = instantiate(keyManagerClasses.get(i));
       }
     }
   }
   if (trustManagers == null) {
     final Sequence<Class<? extends TrustManager>> trustManagerClasses =
         optionMap.get(Options.SSL_JSSE_TRUST_MANAGER_CLASSES);
     if (trustManagerClasses != null) {
       final int size = trustManagerClasses.size();
       trustManagers = new TrustManager[size];
       for (int i = 0; i < size; i++) {
         trustManagers[i] = instantiate(trustManagerClasses.get(i));
       }
     }
   }
   sslContext.init(keyManagers, trustManagers, secureRandom);
   sslContext
       .getClientSessionContext()
       .setSessionCacheSize(optionMap.get(Options.SSL_CLIENT_SESSION_CACHE_SIZE, 0));
   sslContext
       .getClientSessionContext()
       .setSessionTimeout(optionMap.get(Options.SSL_CLIENT_SESSION_TIMEOUT, 0));
   sslContext
       .getServerSessionContext()
       .setSessionCacheSize(optionMap.get(Options.SSL_SERVER_SESSION_CACHE_SIZE, 0));
   sslContext
       .getServerSessionContext()
       .setSessionTimeout(optionMap.get(Options.SSL_SERVER_SESSION_TIMEOUT, 0));
   return sslContext;
 }
 void sendCapRequest(final String remoteServerName) {
   client.trace("Client sending capabilities request");
   // Prepare the request message body
   final Pooled<ByteBuffer> pooledSendBuffer = connection.allocate();
   boolean ok = false;
   try {
     final ByteBuffer sendBuffer = pooledSendBuffer.getResource();
     sendBuffer.put(Protocol.CAPABILITIES);
     ProtocolUtils.writeByte(sendBuffer, Protocol.CAP_VERSION, Protocol.VERSION);
     final String localEndpointName = connectionProviderContext.getEndpoint().getName();
     if (localEndpointName != null) {
       ProtocolUtils.writeString(sendBuffer, Protocol.CAP_ENDPOINT_NAME, localEndpointName);
     }
     ProtocolUtils.writeEmpty(sendBuffer, Protocol.CAP_MESSAGE_CLOSE);
     ProtocolUtils.writeString(
         sendBuffer, Protocol.CAP_VERSION_STRING, Version.getVersionString());
     ProtocolUtils.writeInt(
         sendBuffer,
         Protocol.CAP_CHANNELS_IN,
         optionMap.get(
             RemotingOptions.MAX_INBOUND_CHANNELS, RemotingOptions.DEFAULT_MAX_INBOUND_CHANNELS));
     ProtocolUtils.writeInt(
         sendBuffer,
         Protocol.CAP_CHANNELS_OUT,
         optionMap.get(
             RemotingOptions.MAX_OUTBOUND_CHANNELS,
             RemotingOptions.DEFAULT_MAX_OUTBOUND_CHANNELS));
     sendBuffer.flip();
     connection.setReadListener(new Capabilities(remoteServerName, uri), true);
     connection.send(pooledSendBuffer);
     ok = true;
     // all set
     return;
   } finally {
     if (!ok) {
       pooledSendBuffer.free();
     }
   }
 }
  private synchronized void createConnection() {
    try {
      endpoint = Remoting.createEndpoint("endpoint", OptionMap.EMPTY);
      endpoint.addConnectionProvider(
          "remote",
          new RemoteConnectionProviderFactory(),
          OptionMap.create(Options.SSL_ENABLED, Boolean.FALSE));
      endpoint.addConnectionProvider(
          "http-remoting",
          new HttpUpgradeConnectionProviderFactory(),
          OptionMap.create(Options.SSL_ENABLED, Boolean.FALSE));
      endpoint.addConnectionProvider(
          "https-remoting",
          new HttpUpgradeConnectionProviderFactory(),
          OptionMap.create(Options.SSL_ENABLED, Boolean.TRUE));

      // open a connection
      final IoFuture<Connection> futureConnection =
          endpoint.connect(
              new URI(hostUrl),
              OptionMap.create(
                  Options.SASL_POLICY_NOANONYMOUS,
                  Boolean.FALSE,
                  Options.SASL_POLICY_NOPLAINTEXT,
                  Boolean.FALSE),
              callbackHandler);
      connection = IoFutureHelper.get(futureConnection, 30L, TimeUnit.SECONDS);

      final EJBClientContext ejbClientContext = EJBClientContext.create(classLoader);
      ejbClientContext.registerConnection(connection);

      this.clientContext = ejbClientContext;
    } catch (IOException e) {
      throw new RuntimeException(e);
    } catch (URISyntaxException e) {
      throw new RuntimeException(e);
    }
  }
 @BeforeClass
 public static void setup() throws IOException {
   DefaultServer.setRootHandler(AutobahnWebSocketServer.getRootHandler());
   Xnio xnio = Xnio.getInstance(DefaultServer.class.getClassLoader());
   worker =
       xnio.createWorker(
           OptionMap.builder()
               .set(Options.WORKER_IO_THREADS, 2)
               .set(Options.CONNECTION_HIGH_WATER, 1000000)
               .set(Options.CONNECTION_LOW_WATER, 1000000)
               .set(Options.WORKER_TASK_CORE_THREADS, 30)
               .set(Options.WORKER_TASK_MAX_THREADS, 30)
               .set(Options.TCP_NODELAY, true)
               .set(Options.CORK, true)
               .getMap());
 }
 /**
  * creates option map for remoting connections
  *
  * @param resolver
  * @param model
  * @param defaults
  * @return
  * @throws OperationFailedException
  * @deprecated configuring xnio worker options is no longer supported and should be replaced for
  *     referencing IO subsystem
  */
 @Deprecated
 public static OptionMap create(
     final ExpressionResolver resolver, final ModelNode model, final OptionMap defaults)
     throws OperationFailedException {
   final OptionMap map =
       OptionMap.builder()
           .addAll(defaults)
           .set(
               Options.WORKER_READ_THREADS,
               RemotingSubsystemRootResource.WORKER_READ_THREADS
                   .resolveModelAttribute(resolver, model)
                   .asInt())
           .set(
               Options.WORKER_TASK_CORE_THREADS,
               RemotingSubsystemRootResource.WORKER_TASK_CORE_THREADS
                   .resolveModelAttribute(resolver, model)
                   .asInt())
           .set(
               Options.WORKER_TASK_KEEPALIVE,
               RemotingSubsystemRootResource.WORKER_TASK_KEEPALIVE
                   .resolveModelAttribute(resolver, model)
                   .asInt())
           .set(
               Options.WORKER_TASK_LIMIT,
               RemotingSubsystemRootResource.WORKER_TASK_LIMIT
                   .resolveModelAttribute(resolver, model)
                   .asInt())
           .set(
               Options.WORKER_TASK_MAX_THREADS,
               RemotingSubsystemRootResource.WORKER_TASK_MAX_THREADS
                   .resolveModelAttribute(resolver, model)
                   .asInt())
           .set(
               Options.WORKER_WRITE_THREADS,
               RemotingSubsystemRootResource.WORKER_WRITE_THREADS
                   .resolveModelAttribute(resolver, model)
                   .asInt())
           .set(
               Options.WORKER_READ_THREADS,
               RemotingSubsystemRootResource.WORKER_READ_THREADS
                   .resolveModelAttribute(resolver, model)
                   .asInt())
           .getMap();
   return map;
 }
  @BeforeClass
  public static void setup() {
    final BlockingHandler blockingHandler = new BlockingHandler();
    existing = DefaultServer.getUndertowOptions();
    DefaultServer.setUndertowOptions(OptionMap.create(UndertowOptions.ALWAYS_SET_DATE, false));
    DefaultServer.setRootHandler(blockingHandler);
    blockingHandler.setRootHandler(
        new HttpHandler() {
          @Override
          public void handleRequest(final HttpServerExchange exchange) {
            try {
              if (connection == null) {
                connection = (HttpServerConnection) exchange.getConnection();
              } else if (!DefaultServer.isProxy() && connection != exchange.getConnection()) {
                exchange.setResponseCode(500);
                final OutputStream outputStream = exchange.getOutputStream();
                outputStream.write("Connection not persistent".getBytes());
                outputStream.close();
                return;
              }
              final OutputStream outputStream = exchange.getOutputStream();
              final InputStream inputStream = exchange.getInputStream();
              String m = HttpClientUtils.readResponse(inputStream);
              Assert.assertEquals("abcdefghi", m);

              HeaderMap headers = exchange.getAttachment(HttpAttachments.REQUEST_TRAILERS);
              for (HeaderValues header : headers) {
                for (String val : header) {
                  outputStream.write(header.getHeaderName().toString().getBytes());
                  outputStream.write(": ".getBytes());
                  outputStream.write(val.getBytes());
                  outputStream.write("\r\n".getBytes());
                }
              }

              inputStream.close();
              outputStream.close();
            } catch (IOException e) {
              e.printStackTrace();
              throw new RuntimeException(e);
            }
          }
        });
  }
Example #20
0
 protected static OptionMap getOptions(ModelNode properties) {
   final OptionMap optionMap;
   if (properties.isDefined() && properties.asInt() > 0) {
     OptionMap.Builder builder = OptionMap.builder();
     final ClassLoader loader = SecurityActions.getClassLoader(ConnectorResource.class);
     for (Property property : properties.asPropertyList()) {
       String name = property.getName();
       if (!name.contains(".")) {
         name = "org.xnio.Options." + name;
       }
       final Option option = Option.fromString(name, loader);
       builder.set(
           option,
           option.parseValue(property.getValue().get(CommonAttributes.VALUE).asString(), loader));
     }
     optionMap = builder.getMap();
   } else {
     optionMap = OptionMap.EMPTY;
   }
   return optionMap;
 }
Example #21
0
  static OptionMap createOptionMap(final ModelNode parameters) {
    final OptionMap.Builder builder = OptionMap.builder();

    if (parameters.hasDefined(SASL)) {
      final ModelNode sasl = parameters.require(SASL);
      builder.set(Options.SASL_SERVER_AUTH, sasl.get(SERVER_AUTH).asBoolean());
      builder.set(Options.SASL_STRENGTH, SaslStrength.valueOf(sasl.get(STRENGTH).asString()));
      builder.set(Options.SASL_QOP, Sequence.of(asQopSet(sasl.get(QOP))));
      builder.set(Options.SASL_MECHANISMS, Sequence.of(asStringSet(sasl.get(INCLUDE_MECHANISMS))));

      if (sasl.hasDefined(POLICY)) {
        final ModelNode policy = sasl.require(POLICY);
        builder.set(Options.SASL_POLICY_FORWARD_SECRECY, policy.get(FORWARD_SECRECY).asBoolean());
        builder.set(Options.SASL_POLICY_NOACTIVE, policy.get(NO_ACTIVE).asBoolean());
        builder.set(Options.SASL_POLICY_NOANONYMOUS, policy.get(NO_ANONYMOUS).asBoolean());
        builder.set(Options.SASL_POLICY_NODICTIONARY, policy.get(NO_DICTIONARY).asBoolean());
        builder.set(Options.SASL_POLICY_NOPLAINTEXT, policy.get(NO_PLAIN_TEXT).asBoolean());
        builder.set(Options.SASL_POLICY_PASS_CREDENTIALS, policy.get(PASS_CREDENTIALS).asBoolean());
      }
    }
    return builder.getMap();
  }
 private WebSocketContainer getDefaultContainer() {
   if (defaultContainerDisabled) {
     return null;
   }
   if (defaultContainer != null) {
     return defaultContainer;
   }
   synchronized (UndertowContainerProvider.class) {
     if (defaultContainer == null) {
       try {
         // this is not great, as we have no way to control the lifecycle
         // but there is not much we can do
         // todo: what options should we use here?
         XnioWorker worker =
             Xnio.getInstance().createWorker(OptionMap.create(Options.THREAD_DAEMON, true));
         Pool<ByteBuffer> buffers =
             new ByteBufferSlicePool(
                 directBuffers
                     ? BufferAllocator.DIRECT_BYTE_BUFFER_ALLOCATOR
                     : BufferAllocator.BYTE_BUFFER_ALLOCATOR,
                 1024,
                 10240);
         defaultContainer =
             new ServerWebSocketContainer(
                 defaultIntrospector,
                 UndertowContainerProvider.class.getClassLoader(),
                 worker,
                 buffers,
                 new CompositeThreadSetupAction(Collections.<ThreadSetupAction>emptyList()),
                 !invokeInIoThread);
       } catch (IOException e) {
         throw new RuntimeException(e);
       }
     }
     return defaultContainer;
   }
 }
  private static void setProxyHandler(boolean rewriteHostHeader, boolean reuseXForwarded)
      throws Exception {

    DefaultServer.setRootHandler(
        new ProxyHandler(
            new LoadBalancingProxyClient()
                .setConnectionsPerThread(4)
                .addHost(
                    new URI(
                        "https",
                        null,
                        DefaultServer.getHostAddress("default"),
                        handlerPort,
                        null,
                        null,
                        null),
                    "s1",
                    ssl,
                    OptionMap.create(UndertowOptions.ENABLE_SPDY, false)),
            10000,
            ResponseCodeHandler.HANDLE_404,
            rewriteHostHeader,
            reuseXForwarded));
  }
  @Override
  public synchronized void start(StartContext context) throws StartException {
    super.start(context);

    SecurityRealm realm = securityRealm.getOptionalValue();

    // TODO: SSL support for the client
    // TODO: wire up idle timeout when new version of undertow arrives
    final ModCluster.Builder modClusterBuilder;
    final XnioWorker worker = workerInjectedValue.getValue();
    if (realm == null) {
      modClusterBuilder = ModCluster.builder(worker);
    } else {
      SSLContext sslContext = realm.getSSLContext();
      OptionMap.Builder builder = OptionMap.builder();
      builder.set(Options.USE_DIRECT_BUFFERS, true);
      OptionMap combined = builder.getMap();

      XnioSsl xnioSsl = new UndertowXnioSsl(worker.getXnio(), combined, sslContext);
      modClusterBuilder = ModCluster.builder(worker, UndertowClient.getInstance(), xnioSsl);
    }
    modClusterBuilder
        .setHealthCheckInterval(healthCheckInterval)
        .setMaxRequestTime(maxRequestTime)
        .setCacheConnections(cachedConnections)
        .setQueueNewRequests(requestQueueSize > 0)
        .setRequestQueueSize(requestQueueSize)
        .setRemoveBrokenNodes(removeBrokenNodes)
        .setTtl(connectionIdleTimeout)
        .setMaxConnections(connectionsPerThread)
        .setUseAlias(useAlias);

    modCluster = modClusterBuilder.build();

    MCMPConfig.Builder builder = MCMPConfig.builder();
    InetAddress multicastAddress = advertiseSocketBinding.getValue().getMulticastAddress();
    if (multicastAddress == null) {
      throw UndertowLogger.ROOT_LOGGER.advertiseSocketBindingRequiresMulticastAddress();
    }
    if (advertiseFrequency > 0) {
      builder
          .enableAdvertise()
          .setAdvertiseAddress(
              advertiseSocketBinding.getValue().getSocketAddress().getAddress().getHostAddress())
          .setAdvertiseGroup(multicastAddress.getHostAddress())
          .setAdvertisePort(advertiseSocketBinding.getValue().getPort())
          .setAdvertiseFrequency(advertiseFrequency)
          .setPath(advertisePath)
          .setProtocol(advertiseProtocol)
          .setSecurityKey(securityKey);
    }
    builder.setManagementHost(managementSocketBinding.getValue().getSocketAddress().getHostName());
    builder.setManagementPort(managementSocketBinding.getValue().getSocketAddress().getPort());

    config = builder.build();

    if (advertiseFrequency > 0) {
      try {
        modCluster.advertise(config);
      } catch (IOException e) {
        throw new RuntimeException(e);
      }
    }
    modCluster.start();
  }
Example #25
0
  public synchronized void start() {
    xnio = Xnio.getInstance(Undertow.class.getClassLoader());
    channels = new ArrayList<>();
    try {
      worker =
          xnio.createWorker(
              OptionMap.builder()
                  .set(Options.WORKER_IO_THREADS, ioThreads)
                  .set(Options.CONNECTION_HIGH_WATER, 1000000)
                  .set(Options.CONNECTION_LOW_WATER, 1000000)
                  .set(Options.WORKER_TASK_CORE_THREADS, workerThreads)
                  .set(Options.WORKER_TASK_MAX_THREADS, workerThreads)
                  .set(Options.TCP_NODELAY, true)
                  .set(Options.CORK, true)
                  .addAll(workerOptions)
                  .getMap());

      OptionMap socketOptions =
          OptionMap.builder()
              .set(Options.WORKER_IO_THREADS, ioThreads)
              .set(Options.TCP_NODELAY, true)
              .set(Options.REUSE_ADDRESSES, true)
              .set(Options.BALANCING_TOKENS, 1)
              .set(Options.BALANCING_CONNECTIONS, 2)
              .set(Options.BACKLOG, 1000)
              .addAll(this.socketOptions)
              .getMap();

      Pool<ByteBuffer> buffers =
          new ByteBufferSlicePool(
              directBuffers
                  ? BufferAllocator.DIRECT_BYTE_BUFFER_ALLOCATOR
                  : BufferAllocator.BYTE_BUFFER_ALLOCATOR,
              bufferSize,
              bufferSize * buffersPerRegion);

      for (ListenerConfig listener : listeners) {
        final HttpHandler rootHandler =
            listener.rootHandler != null ? listener.rootHandler : this.rootHandler;
        if (listener.type == ListenerType.AJP) {
          AjpOpenListener openListener = new AjpOpenListener(buffers, serverOptions);
          openListener.setRootHandler(rootHandler);
          ChannelListener<AcceptingChannel<StreamConnection>> acceptListener =
              ChannelListeners.openListenerAdapter(openListener);
          AcceptingChannel<? extends StreamConnection> server =
              worker.createStreamConnectionServer(
                  new InetSocketAddress(Inet4Address.getByName(listener.host), listener.port),
                  acceptListener,
                  socketOptions);
          server.resumeAccepts();
          channels.add(server);
        } else {
          OptionMap undertowOptions =
              OptionMap.builder()
                  .set(UndertowOptions.BUFFER_PIPELINED_DATA, true)
                  .addAll(serverOptions)
                  .getMap();
          if (listener.type == ListenerType.HTTP) {
            HttpOpenListener openListener = new HttpOpenListener(buffers, undertowOptions);
            openListener.setRootHandler(rootHandler);
            ChannelListener<AcceptingChannel<StreamConnection>> acceptListener =
                ChannelListeners.openListenerAdapter(openListener);
            AcceptingChannel<? extends StreamConnection> server =
                worker.createStreamConnectionServer(
                    new InetSocketAddress(Inet4Address.getByName(listener.host), listener.port),
                    acceptListener,
                    socketOptions);
            server.resumeAccepts();
            channels.add(server);
          } else if (listener.type == ListenerType.HTTPS) {
            ChannelListener<StreamConnection> openListener;

            HttpOpenListener httpOpenListener = new HttpOpenListener(buffers, undertowOptions);
            httpOpenListener.setRootHandler(rootHandler);

            boolean spdy = serverOptions.get(UndertowOptions.ENABLE_SPDY, false);
            boolean http2 = serverOptions.get(UndertowOptions.ENABLE_HTTP2, false);
            if (spdy || http2) {
              AlpnOpenListener alpn =
                  new AlpnOpenListener(buffers, undertowOptions, httpOpenListener);
              if (spdy) {
                SpdyOpenListener spdyListener =
                    new SpdyOpenListener(
                        buffers,
                        new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 1024, 1024),
                        undertowOptions);
                spdyListener.setRootHandler(rootHandler);
                alpn.addProtocol(SpdyOpenListener.SPDY_3_1, spdyListener, 5);
              }
              if (http2) {
                Http2OpenListener http2Listener = new Http2OpenListener(buffers, undertowOptions);
                http2Listener.setRootHandler(rootHandler);
                alpn.addProtocol(Http2OpenListener.HTTP2, http2Listener, 10);
                alpn.addProtocol(Http2OpenListener.HTTP2_14, http2Listener, 7);
              }
              openListener = alpn;
            } else {
              openListener = httpOpenListener;
            }
            ChannelListener<AcceptingChannel<StreamConnection>> acceptListener =
                ChannelListeners.openListenerAdapter(openListener);
            XnioSsl xnioSsl;
            if (listener.sslContext != null) {
              xnioSsl =
                  new UndertowXnioSsl(
                      xnio,
                      OptionMap.create(Options.USE_DIRECT_BUFFERS, true),
                      listener.sslContext);
            } else {
              xnioSsl =
                  xnio.getSslProvider(
                      listener.keyManagers,
                      listener.trustManagers,
                      OptionMap.create(Options.USE_DIRECT_BUFFERS, true));
            }
            AcceptingChannel<SslConnection> sslServer =
                xnioSsl.createSslConnectionServer(
                    worker,
                    new InetSocketAddress(Inet4Address.getByName(listener.host), listener.port),
                    (ChannelListener) acceptListener,
                    socketOptions);
            sslServer.resumeAccepts();
            channels.add(sslServer);
          }
        }
      }

    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }
/** @author Alexey Loubyansky */
public class CLIModelControllerClient extends AbstractModelControllerClient {

  private static final OptionMap DEFAULT_OPTIONS =
      OptionMap.create(
          RemotingOptions.TRANSMIT_WINDOW_SIZE,
          ProtocolChannelClient.Configuration.DEFAULT_WINDOW_SIZE,
          RemotingOptions.RECEIVE_WINDOW_SIZE,
          ProtocolChannelClient.Configuration.DEFAULT_WINDOW_SIZE);

  private static final ThreadPoolExecutor executorService;
  private static final Endpoint endpoint;

  static {
    final BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<Runnable>();
    final ThreadFactory threadFactory =
        new JBossThreadFactory(
            new ThreadGroup("cli-remoting"),
            Boolean.FALSE,
            null,
            "%G - %t",
            null,
            null,
            doPrivileged(GetAccessControlContextAction.getInstance()));
    executorService = new ThreadPoolExecutor(2, 4, 60L, TimeUnit.SECONDS, workQueue, threadFactory);
    // Allow the core threads to time out as well
    executorService.allowCoreThreadTimeOut(true);

    try {
      endpoint = Remoting.createEndpoint("cli-client", OptionMap.EMPTY);
      endpoint.addConnectionProvider(
          "remote", new RemoteConnectionProviderFactory(), OptionMap.EMPTY);
      endpoint.addConnectionProvider(
          "http-remoting",
          new HttpUpgradeConnectionProviderFactory(),
          OptionMap.create(Options.SSL_ENABLED, Boolean.FALSE));
      endpoint.addConnectionProvider(
          "https-remoting",
          new HttpUpgradeConnectionProviderFactory(),
          OptionMap.create(Options.SSL_ENABLED, Boolean.TRUE));
    } catch (IOException e) {
      throw new IllegalStateException("Failed to create remoting endpoint", e);
    }

    CliShutdownHook.add(
        new CliShutdownHook.Handler() {
          @Override
          public void shutdown() {
            executorService.shutdown();
            try {
              executorService.awaitTermination(1, TimeUnit.SECONDS);
            } catch (InterruptedException e) {
            }
            try {
              endpoint.close();
            } catch (IOException e) {
            }
          }
        });
  }

  private final Object lock = "lock";

  private final CallbackHandler handler;
  private final SSLContext sslContext;
  private final ConnectionCloseHandler closeHandler;

  private final ManagementChannelHandler channelAssociation;
  private ManagementClientChannelStrategy strategy;
  private final ProtocolChannelClient.Configuration channelConfig;
  private boolean closed;

  CLIModelControllerClient(
      final String protocol,
      CallbackHandler handler,
      String hostName,
      int connectionTimeout,
      final ConnectionCloseHandler closeHandler,
      int port,
      SSLContext sslContext)
      throws IOException {
    this.handler = handler;
    this.sslContext = sslContext;
    this.closeHandler = closeHandler;

    this.channelAssociation =
        new ManagementChannelHandler(
            new ManagementClientChannelStrategy() {
              @Override
              public Channel getChannel() throws IOException {
                return getOrCreateChannel();
              }

              @Override
              public void close() throws IOException {}
            },
            executorService,
            this);

    channelConfig = new ProtocolChannelClient.Configuration();
    try {
      channelConfig.setUri(
          new URI(protocol + "://" + formatPossibleIpv6Address(hostName) + ":" + port));
    } catch (URISyntaxException e) {
      throw new IOException("Failed to create URI", e);
    }
    channelConfig.setOptionMap(DEFAULT_OPTIONS);
    if (connectionTimeout > 0) {
      channelConfig.setConnectionTimeout(connectionTimeout);
    }
    channelConfig.setEndpoint(endpoint);
  }

  @Override
  protected ManagementChannelAssociation getChannelAssociation() throws IOException {
    return channelAssociation;
  }

  protected Channel getOrCreateChannel() throws IOException {
    synchronized (lock) {
      if (strategy == null) {

        final ProtocolChannelClient setup = ProtocolChannelClient.create(channelConfig);
        final ChannelCloseHandler channelCloseHandler = new ChannelCloseHandler();
        strategy =
            ManagementClientChannelStrategy.create(
                setup, channelAssociation, handler, null, sslContext, channelCloseHandler);
        channelCloseHandler.setOriginalStrategy(strategy);
      }
      lock.notifyAll();
      return strategy.getChannel();
    }
  }

  public boolean isConnected() {
    return strategy != null;
  }

  @Override
  public void close() throws IOException {
    if (closed) {
      return;
    }
    synchronized (lock) {
      if (closed) {
        return;
      }
      closed = true;
      // Don't allow any new request
      channelAssociation.shutdown();
      // First close the channel and connection
      if (strategy != null) {
        StreamUtils.safeClose(strategy);
        strategy = null;
      }
      // Cancel all still active operations
      channelAssociation.shutdownNow();
      try {
        channelAssociation.awaitCompletion(1, TimeUnit.SECONDS);
      } catch (InterruptedException ignore) {
        Thread.currentThread().interrupt();
      }
      lock.notifyAll();
    }
  }

  public ModelNode execute(ModelNode operation, boolean awaitClose) throws IOException {
    final ModelNode response = super.execute(operation);
    if (!Util.isSuccess(response)) {
      return response;
    }

    if (awaitClose) {
      synchronized (lock) {
        if (strategy != null) {
          try {
            lock.wait(5000);
          } catch (InterruptedException e) {
          }
          StreamUtils.safeClose(strategy);
          strategy = null;
        }
      }
    }

    return response;
  }

  public boolean isClosed() {
    return closed;
  }

  public void ensureConnected(long timeoutMillis) throws CommandLineException {
    boolean doTry = true;
    final long start = System.currentTimeMillis();
    IOException ioe = null;
    while (doTry) {
      synchronized (lock) {
        try {
          getOrCreateChannel().getConnection();
          doTry = false;
        } catch (IOException e) {
          ioe = e;
          if (strategy != null) {
            StreamUtils.safeClose(strategy);
            strategy = null;
          }
        }
        lock.notifyAll();
      }

      if (ioe != null) {
        if (System.currentTimeMillis() - start > timeoutMillis) {
          throw new CommandLineException(
              "Failed to establish connection in " + (System.currentTimeMillis() - start) + "ms",
              ioe);
        }
        ioe = null;
        try {
          Thread.sleep(500);
        } catch (InterruptedException e) {
          throw new CommandLineException("Interrupted while pausing before reconnecting.", e);
        }
      }
    }
  }

  private static String formatPossibleIpv6Address(String address) {
    if (address == null) {
      return address;
    }
    if (!address.contains(":")) {
      return address;
    }
    if (address.startsWith("[") && address.endsWith("]")) {
      return address;
    }
    return "[" + address + "]";
  }

  private final class ChannelCloseHandler implements CloseHandler<Channel> {

    private ManagementClientChannelStrategy originalStrategy;

    void setOriginalStrategy(ManagementClientChannelStrategy strategy) {
      if (originalStrategy != null) {
        throw new IllegalArgumentException("The strategy has already been initialized.");
      }
      originalStrategy = strategy;
    }

    @Override
    public void handleClose(final Channel closed, final IOException exception) {
      if (CLIModelControllerClient.this.closed) {
        return;
      }
      synchronized (lock) {
        if (strategy != null) {
          if (strategy != originalStrategy) {
            new Exception("Channel close handler " + strategy + " " + originalStrategy)
                .printStackTrace();
          }
          strategy = null;
          closeHandler.handleClose();
        }
        channelAssociation.handleChannelClosed(closed, exception);
        lock.notifyAll();
      }
      // Closing the strategy in this handler may result in race conditions
      // with connection closing and then deadlocks in remoting
      // it's safer to close the strategy from the connection close handler
      closed
          .getConnection()
          .addCloseHandler(
              new CloseHandler<Connection>() {
                @Override
                public void handleClose(Connection closed, IOException exception) {
                  StreamUtils.safeClose(originalStrategy);
                }
              });
    }
  }
}
Example #27
0
  public static final class Builder {

    private int bufferSize;
    private int buffersPerRegion;
    private int ioThreads;
    private int workerThreads;
    private boolean directBuffers;
    private final List<ListenerConfig> listeners = new ArrayList<>();
    private HttpHandler handler;

    private final OptionMap.Builder workerOptions = OptionMap.builder();
    private final OptionMap.Builder socketOptions = OptionMap.builder();
    private final OptionMap.Builder serverOptions = OptionMap.builder();

    private Builder() {
      ioThreads = Math.max(Runtime.getRuntime().availableProcessors(), 2);
      workerThreads = ioThreads * 8;
      long maxMemory = Runtime.getRuntime().maxMemory();
      // smaller than 64mb of ram we use 512b buffers
      if (maxMemory < 64 * 1024 * 1024) {
        // use 512b buffers
        directBuffers = false;
        bufferSize = 512;
        buffersPerRegion = 10;
      } else if (maxMemory < 128 * 1024 * 1024) {
        // use 1k buffers
        directBuffers = true;
        bufferSize = 1024;
        buffersPerRegion = 10;
      } else {
        // use 16k buffers for best performance
        // as 16k is generally the max amount of data that can be sent in a single write() call
        directBuffers = true;
        bufferSize = 1024 * 16;
        buffersPerRegion = 20;
      }
    }

    public Undertow build() {
      return new Undertow(this);
    }

    @Deprecated
    public Builder addListener(int port, String host) {
      listeners.add(new ListenerConfig(ListenerType.HTTP, port, host, null, null, null));
      return this;
    }

    @Deprecated
    public Builder addListener(int port, String host, ListenerType listenerType) {
      listeners.add(new ListenerConfig(listenerType, port, host, null, null, null));
      return this;
    }

    public Builder addHttpListener(int port, String host) {
      listeners.add(new ListenerConfig(ListenerType.HTTP, port, host, null, null, null));
      return this;
    }

    public Builder addHttpsListener(
        int port, String host, KeyManager[] keyManagers, TrustManager[] trustManagers) {
      listeners.add(
          new ListenerConfig(ListenerType.HTTPS, port, host, keyManagers, trustManagers, null));
      return this;
    }

    public Builder addHttpsListener(int port, String host, SSLContext sslContext) {
      listeners.add(new ListenerConfig(ListenerType.HTTPS, port, host, sslContext, null));
      return this;
    }

    public Builder addAjpListener(int port, String host) {
      listeners.add(new ListenerConfig(ListenerType.AJP, port, host, null, null, null));
      return this;
    }

    public Builder addHttpListener(int port, String host, HttpHandler rootHandler) {
      listeners.add(new ListenerConfig(ListenerType.HTTP, port, host, null, null, rootHandler));
      return this;
    }

    public Builder addHttpsListener(
        int port,
        String host,
        KeyManager[] keyManagers,
        TrustManager[] trustManagers,
        HttpHandler rootHandler) {
      listeners.add(
          new ListenerConfig(
              ListenerType.HTTPS, port, host, keyManagers, trustManagers, rootHandler));
      return this;
    }

    public Builder addHttpsListener(
        int port, String host, SSLContext sslContext, HttpHandler rootHandler) {
      listeners.add(new ListenerConfig(ListenerType.HTTPS, port, host, sslContext, rootHandler));
      return this;
    }

    public Builder addAjpListener(int port, String host, HttpHandler rootHandler) {
      listeners.add(new ListenerConfig(ListenerType.AJP, port, host, null, null, rootHandler));
      return this;
    }

    public Builder setBufferSize(final int bufferSize) {
      this.bufferSize = bufferSize;
      return this;
    }

    public Builder setBuffersPerRegion(final int buffersPerRegion) {
      this.buffersPerRegion = buffersPerRegion;
      return this;
    }

    public Builder setIoThreads(final int ioThreads) {
      this.ioThreads = ioThreads;
      return this;
    }

    public Builder setWorkerThreads(final int workerThreads) {
      this.workerThreads = workerThreads;
      return this;
    }

    public Builder setDirectBuffers(final boolean directBuffers) {
      this.directBuffers = directBuffers;
      return this;
    }

    public Builder setHandler(final HttpHandler handler) {
      this.handler = handler;
      return this;
    }

    public <T> Builder setServerOption(final Option<T> option, final T value) {
      serverOptions.set(option, value);
      return this;
    }

    public <T> Builder setSocketOption(final Option<T> option, final T value) {
      socketOptions.set(option, value);
      return this;
    }

    public <T> Builder setWorkerOption(final Option<T> option, final T value) {
      workerOptions.set(option, value);
      return this;
    }
  }
/** @author Tomaz Cerar */
public abstract class ListenerService<T> implements Service<T> {

  protected static final OptionMap commonOptions =
      OptionMap.builder()
          .set(Options.TCP_NODELAY, true)
          .set(Options.REUSE_ADDRESSES, true)
          .getMap();
  protected final InjectedValue<XnioWorker> worker = new InjectedValue<>();
  protected final InjectedValue<SocketBinding> binding = new InjectedValue<>();
  protected final InjectedValue<SocketBinding> redirectSocket = new InjectedValue<>();
  protected final InjectedValue<Pool> bufferPool = new InjectedValue<>();
  protected final InjectedValue<Server> serverService = new InjectedValue<>();
  protected final List<HandlerWrapper> listenerHandlerWrappers = new ArrayList<>();

  private final String name;
  protected final OptionMap listenerOptions;
  protected volatile OpenListener openListener;

  protected ListenerService(String name, OptionMap listenerOptions) {
    this.name = name;
    this.listenerOptions = listenerOptions;
  }

  public InjectedValue<XnioWorker> getWorker() {
    return worker;
  }

  public InjectedValue<SocketBinding> getBinding() {
    return binding;
  }

  public InjectedValue<SocketBinding> getRedirectSocket() {
    return redirectSocket;
  }

  public InjectedValue<Pool> getBufferPool() {
    return bufferPool;
  }

  public InjectedValue<Server> getServerService() {
    return serverService;
  }

  protected int getBufferSize() {
    return 8192;
  }

  public String getName() {
    return name;
  }

  public abstract boolean isSecure();

  protected void registerBinding() {
    binding
        .getValue()
        .getSocketBindings()
        .getNamedRegistry()
        .registerBinding(new ListenerBinding(binding.getValue()));
  }

  protected void unregisterBinding() {
    final SocketBinding binding = this.binding.getValue();
    binding.getSocketBindings().getNamedRegistry().unregisterBinding(binding.getName());
  }

  protected abstract void preStart(StartContext context);

  @Override
  public void start(StartContext context) throws StartException {
    preStart(context);
    serverService.getValue().registerListener(this);
    try {
      final InetSocketAddress socketAddress = binding.getValue().getSocketAddress();
      openListener = createOpenListener();
      final ChannelListener<AcceptingChannel<StreamConnection>> acceptListener =
          ChannelListeners.openListenerAdapter(openListener);
      HttpHandler handler = serverService.getValue().getRoot();
      for (HandlerWrapper wrapper : listenerHandlerWrappers) {
        handler = wrapper.wrap(handler);
      }
      openListener.setRootHandler(handler);
      startListening(worker.getValue(), socketAddress, acceptListener);
      registerBinding();
    } catch (IOException e) {
      throw new StartException("Could not start http listener", e);
    }
  }

  @Override
  public void stop(StopContext context) {
    serverService.getValue().unregisterListener(this);
    stopListening();
    unregisterBinding();
  }

  protected abstract OpenListener createOpenListener();

  abstract void startListening(
      XnioWorker worker,
      InetSocketAddress socketAddress,
      ChannelListener<AcceptingChannel<StreamConnection>> acceptListener)
      throws IOException;

  abstract void stopListening();

  protected abstract String getProtocol();

  private static class ListenerBinding implements ManagedBinding {

    private final SocketBinding binding;

    private ListenerBinding(final SocketBinding binding) {
      this.binding = binding;
    }

    @Override
    public String getSocketBindingName() {
      return binding.getName();
    }

    @Override
    public InetSocketAddress getBindAddress() {
      return binding.getSocketAddress();
    }

    @Override
    public void close() throws IOException {}
  }
}
  public void handleEvent(final ConnectedMessageChannel channel) {
    int res;
    SaslWrapper saslWrapper = connection.getSaslWrapper();
    try {
      Pooled<ByteBuffer> pooled = connection.allocate();
      ByteBuffer buffer = pooled.getResource();
      try {
        for (; ; )
          try {
            res = channel.receive(buffer);
            if (res == -1) {
              log.trace("Received connection end-of-stream");
              try {
                channel.shutdownReads();
              } finally {
                handler.handleConnectionClose();
              }
              return;
            } else if (res == 0) {
              log.trace("No message ready; returning");
              return;
            }
            buffer.flip();
            if (saslWrapper != null) {
              final ByteBuffer source = buffer.duplicate();
              buffer.clear();
              saslWrapper.unwrap(buffer, source);
              buffer.flip();
            }
            final byte protoId = buffer.get();
            try {
              switch (protoId) {
                case Protocol.CONNECTION_ALIVE:
                  {
                    log.trace("Received connection alive");
                    connection.sendAliveResponse();
                    return;
                  }
                case Protocol.CONNECTION_ALIVE_ACK:
                  {
                    log.trace("Received connection alive ack");
                    return;
                  }
                case Protocol.CONNECTION_CLOSE:
                  {
                    log.trace("Received connection close request");
                    handler.receiveCloseRequest();
                    return;
                  }
                case Protocol.CHANNEL_OPEN_REQUEST:
                  {
                    log.trace("Received channel open request");
                    int channelId = buffer.getInt() ^ 0x80000000;
                    int inboundWindow = Integer.MAX_VALUE;
                    int inboundMessages = 0xffff;
                    int outboundWindow = Integer.MAX_VALUE;
                    int outboundMessages = 0xffff;
                    long inboundMessageSize = Long.MAX_VALUE;
                    long outboundMessageSize = Long.MAX_VALUE;
                    // parse out request
                    int b;
                    String serviceType = null;
                    OUT:
                    for (; ; ) {
                      b = buffer.get() & 0xff;
                      switch (b) {
                        case Protocol.O_END:
                          break OUT;
                        case Protocol.O_SERVICE_NAME:
                          {
                            serviceType = ProtocolUtils.readString(buffer);
                            break;
                          }
                        case Protocol.O_MAX_INBOUND_MSG_WINDOW_SIZE:
                          {
                            outboundWindow =
                                Math.min(outboundWindow, ProtocolUtils.readInt(buffer));
                            break;
                          }
                        case Protocol.O_MAX_INBOUND_MSG_COUNT:
                          {
                            outboundMessages =
                                Math.min(outboundMessages, ProtocolUtils.readUnsignedShort(buffer));
                            break;
                          }
                        case Protocol.O_MAX_OUTBOUND_MSG_WINDOW_SIZE:
                          {
                            inboundWindow = Math.min(inboundWindow, ProtocolUtils.readInt(buffer));
                            break;
                          }
                        case Protocol.O_MAX_OUTBOUND_MSG_COUNT:
                          {
                            inboundMessages =
                                Math.min(inboundMessages, ProtocolUtils.readUnsignedShort(buffer));
                            break;
                          }
                        case Protocol.O_MAX_INBOUND_MSG_SIZE:
                          {
                            outboundMessageSize =
                                Math.min(outboundMessageSize, ProtocolUtils.readLong(buffer));
                            break;
                          }
                        case Protocol.O_MAX_OUTBOUND_MSG_SIZE:
                          {
                            inboundMessageSize =
                                Math.min(inboundMessageSize, ProtocolUtils.readLong(buffer));
                            break;
                          }
                        default:
                          {
                            Buffers.skip(buffer, buffer.get() & 0xff);
                            break;
                          }
                      }
                    }
                    if ((channelId & 0x80000000) != 0) {
                      // invalid channel ID, original should have had MSB=1 and thus the complement
                      // should be MSB=0
                      refuseService(channelId, "Invalid channel ID");
                      break;
                    }

                    if (serviceType == null) {
                      // invalid service reply
                      refuseService(channelId, "Missing service name");
                      break;
                    }

                    final RegisteredService registeredService =
                        handler.getConnectionContext().getRegisteredService(serviceType);
                    if (registeredService == null) {
                      refuseService(channelId, "Unknown service name");
                      break;
                    }
                    final OptionMap serviceOptionMap = registeredService.getOptionMap();
                    outboundWindow =
                        Math.min(
                            outboundWindow,
                            serviceOptionMap.get(
                                RemotingOptions.TRANSMIT_WINDOW_SIZE,
                                Protocol.DEFAULT_WINDOW_SIZE));
                    outboundMessages =
                        Math.min(
                            outboundMessages,
                            serviceOptionMap.get(
                                RemotingOptions.MAX_OUTBOUND_MESSAGES,
                                Protocol.DEFAULT_MESSAGE_COUNT));
                    inboundWindow =
                        Math.min(
                            inboundWindow,
                            serviceOptionMap.get(
                                RemotingOptions.RECEIVE_WINDOW_SIZE, Protocol.DEFAULT_WINDOW_SIZE));
                    inboundMessages =
                        Math.min(
                            inboundMessages,
                            serviceOptionMap.get(
                                RemotingOptions.MAX_INBOUND_MESSAGES,
                                Protocol.DEFAULT_MESSAGE_COUNT));
                    outboundMessageSize =
                        Math.min(
                            outboundMessageSize,
                            serviceOptionMap.get(
                                RemotingOptions.MAX_OUTBOUND_MESSAGE_SIZE, Long.MAX_VALUE));
                    inboundMessageSize =
                        Math.min(
                            inboundMessageSize,
                            serviceOptionMap.get(
                                RemotingOptions.MAX_INBOUND_MESSAGE_SIZE, Long.MAX_VALUE));

                    final OpenListener openListener = registeredService.getOpenListener();
                    if (!handler.handleInboundChannelOpen()) {
                      // refuse
                      refuseService(channelId, "Channel refused");
                      break;
                    }
                    boolean ok1 = false;
                    try {
                      // construct the channel
                      RemoteConnectionChannel connectionChannel =
                          new RemoteConnectionChannel(
                              handler,
                              connection,
                              channelId,
                              outboundWindow,
                              inboundWindow,
                              outboundMessages,
                              inboundMessages,
                              outboundMessageSize,
                              inboundMessageSize);
                      RemoteConnectionChannel existing = handler.addChannel(connectionChannel);
                      if (existing != null) {
                        log.tracef("Encountered open request for duplicate %s", existing);
                        // the channel already exists, which means the remote side "forgot" about it
                        // or we somehow missed the close message.
                        // the only safe thing to do is to terminate the existing channel.
                        try {
                          refuseService(channelId, "Duplicate ID");
                        } finally {
                          existing.handleRemoteClose();
                        }
                        break;
                      }

                      // construct reply
                      Pooled<ByteBuffer> pooledReply = connection.allocate();
                      boolean ok2 = false;
                      try {
                        ByteBuffer replyBuffer = pooledReply.getResource();
                        replyBuffer.clear();
                        replyBuffer.put(Protocol.CHANNEL_OPEN_ACK);
                        replyBuffer.putInt(channelId);
                        ProtocolUtils.writeInt(
                            replyBuffer, Protocol.O_MAX_INBOUND_MSG_WINDOW_SIZE, inboundWindow);
                        ProtocolUtils.writeShort(
                            replyBuffer, Protocol.O_MAX_INBOUND_MSG_COUNT, inboundMessages);
                        if (inboundMessageSize != Long.MAX_VALUE) {
                          ProtocolUtils.writeLong(
                              replyBuffer, Protocol.O_MAX_INBOUND_MSG_SIZE, inboundMessageSize);
                        }
                        ProtocolUtils.writeInt(
                            replyBuffer, Protocol.O_MAX_OUTBOUND_MSG_WINDOW_SIZE, outboundWindow);
                        ProtocolUtils.writeShort(
                            replyBuffer, Protocol.O_MAX_OUTBOUND_MSG_COUNT, outboundMessages);
                        if (outboundMessageSize != Long.MAX_VALUE) {
                          ProtocolUtils.writeLong(
                              replyBuffer, Protocol.O_MAX_OUTBOUND_MSG_SIZE, outboundMessageSize);
                        }
                        replyBuffer.put((byte) 0);
                        replyBuffer.flip();
                        ok2 = true;
                        // send takes ownership of the buffer
                        connection.send(pooledReply);
                      } finally {
                        if (!ok2) pooledReply.free();
                      }

                      ok1 = true;

                      // Call the service open listener
                      connection
                          .getExecutor()
                          .execute(SpiUtils.getServiceOpenTask(connectionChannel, openListener));
                      break;
                    } finally {
                      // the inbound channel wasn't open so don't leak the ref count
                      if (!ok1) handler.handleInboundChannelClosed();
                    }
                  }
                case Protocol.MESSAGE_DATA:
                  {
                    log.trace("Received message data");
                    int channelId = buffer.getInt() ^ 0x80000000;
                    RemoteConnectionChannel connectionChannel = handler.getChannel(channelId);
                    if (connectionChannel == null) {
                      // ignore the data
                      log.tracef("Ignoring message data for expired channel");
                      break;
                    }
                    connectionChannel.handleMessageData(pooled);
                    // need a new buffer now
                    pooled = connection.allocate();
                    buffer = pooled.getResource();
                    break;
                  }
                case Protocol.MESSAGE_WINDOW_OPEN:
                  {
                    log.trace("Received message window open");
                    int channelId = buffer.getInt() ^ 0x80000000;
                    RemoteConnectionChannel connectionChannel = handler.getChannel(channelId);
                    if (connectionChannel == null) {
                      // ignore
                      log.tracef("Ignoring window open for expired channel");
                      break;
                    }
                    connectionChannel.handleWindowOpen(pooled);
                    break;
                  }
                case Protocol.MESSAGE_CLOSE:
                  {
                    log.trace("Received message async close");
                    int channelId = buffer.getInt() ^ 0x80000000;
                    RemoteConnectionChannel connectionChannel = handler.getChannel(channelId);
                    if (connectionChannel == null) {
                      break;
                    }
                    connectionChannel.handleAsyncClose(pooled);
                    break;
                  }
                case Protocol.CHANNEL_CLOSED:
                  {
                    log.trace("Received channel closed");
                    int channelId = buffer.getInt() ^ 0x80000000;
                    RemoteConnectionChannel connectionChannel = handler.getChannel(channelId);
                    if (connectionChannel == null) {
                      break;
                    }
                    connectionChannel.handleRemoteClose();
                    break;
                  }
                case Protocol.CHANNEL_SHUTDOWN_WRITE:
                  {
                    log.trace("Received channel shutdown write");
                    int channelId = buffer.getInt() ^ 0x80000000;
                    RemoteConnectionChannel connectionChannel = handler.getChannel(channelId);
                    if (connectionChannel == null) {
                      break;
                    }
                    connectionChannel.handleIncomingWriteShutdown();
                    break;
                  }
                case Protocol.CHANNEL_OPEN_ACK:
                  {
                    log.trace("Received channel open ack");
                    int channelId = buffer.getInt() ^ 0x80000000;
                    if ((channelId & 0x80000000) == 0) {
                      // invalid
                      break;
                    }
                    PendingChannel pendingChannel = handler.removePendingChannel(channelId);
                    if (pendingChannel == null) {
                      // invalid
                      break;
                    }
                    int outboundWindow = pendingChannel.getOutboundWindowSize();
                    int inboundWindow = pendingChannel.getInboundWindowSize();
                    int outboundMessageCount = pendingChannel.getOutboundMessageCount();
                    int inboundMessageCount = pendingChannel.getInboundMessageCount();
                    long outboundMessageSize = pendingChannel.getOutboundMessageSize();
                    long inboundMessageSize = pendingChannel.getInboundMessageSize();
                    OUT:
                    for (; ; ) {
                      switch (buffer.get() & 0xff) {
                        case Protocol.O_MAX_INBOUND_MSG_WINDOW_SIZE:
                          {
                            outboundWindow =
                                Math.min(outboundWindow, ProtocolUtils.readInt(buffer));
                            break;
                          }
                        case Protocol.O_MAX_INBOUND_MSG_COUNT:
                          {
                            outboundMessageCount =
                                Math.min(
                                    outboundMessageCount, ProtocolUtils.readUnsignedShort(buffer));
                            break;
                          }
                        case Protocol.O_MAX_OUTBOUND_MSG_WINDOW_SIZE:
                          {
                            inboundWindow = Math.min(inboundWindow, ProtocolUtils.readInt(buffer));
                            break;
                          }
                        case Protocol.O_MAX_OUTBOUND_MSG_COUNT:
                          {
                            inboundMessageCount =
                                Math.min(
                                    inboundMessageCount, ProtocolUtils.readUnsignedShort(buffer));
                            break;
                          }
                        case Protocol.O_MAX_INBOUND_MSG_SIZE:
                          {
                            outboundMessageSize =
                                Math.min(outboundMessageSize, ProtocolUtils.readLong(buffer));
                            break;
                          }
                        case Protocol.O_MAX_OUTBOUND_MSG_SIZE:
                          {
                            inboundMessageSize =
                                Math.min(inboundMessageSize, ProtocolUtils.readLong(buffer));
                            break;
                          }
                        case Protocol.O_END:
                          {
                            break OUT;
                          }
                        default:
                          {
                            // ignore unknown parameter
                            Buffers.skip(buffer, buffer.get() & 0xff);
                            break;
                          }
                      }
                    }
                    RemoteConnectionChannel newChannel =
                        new RemoteConnectionChannel(
                            handler,
                            connection,
                            channelId,
                            outboundWindow,
                            inboundWindow,
                            outboundMessageCount,
                            inboundMessageCount,
                            outboundMessageSize,
                            inboundMessageSize);
                    handler.putChannel(newChannel);
                    pendingChannel.getResult().setResult(newChannel);
                    break;
                  }
                case Protocol.SERVICE_ERROR:
                  {
                    log.trace("Received service error");
                    int channelId = buffer.getInt() ^ 0x80000000;
                    PendingChannel pendingChannel = handler.removePendingChannel(channelId);
                    if (pendingChannel == null) {
                      // invalid
                      break;
                    }
                    String reason = new String(Buffers.take(buffer), Protocol.UTF_8);
                    pendingChannel.getResult().setException(new IOException(reason));
                    break;
                  }
                default:
                  {
                    log.unknownProtocolId(protoId);
                    break;
                  }
              }
            } catch (BufferUnderflowException e) {
              log.bufferUnderflow(protoId);
            }
          } catch (BufferUnderflowException e) {
            log.bufferUnderflowRaw();
          } finally {
            buffer.clear();
          }
      } finally {
        pooled.free();
      }
    } catch (IOException e) {
      connection.handleException(e);
      handler.handleConnectionClose();
    }
  }
    public void handleEvent(final ConnectedMessageChannel channel) {
      final Pooled<ByteBuffer> pooledReceiveBuffer = connection.allocate();
      try {
        final ByteBuffer receiveBuffer = pooledReceiveBuffer.getResource();
        int res = 0;
        try {
          res = channel.receive(receiveBuffer);
        } catch (IOException e) {
          connection.handleException(e);
          return;
        }
        if (res == -1) {
          connection.handleException(client.abruptClose(connection));
          return;
        }
        if (res == 0) {
          return;
        }
        receiveBuffer.flip();
        boolean starttls = false;
        final Set<String> saslMechs = new LinkedHashSet<String>();
        final byte msgType = receiveBuffer.get();
        switch (msgType) {
          case Protocol.CONNECTION_ALIVE:
            {
              client.trace("Client received connection alive");
              return;
            }
          case Protocol.CONNECTION_CLOSE:
            {
              client.trace("Client received connection close request");
              connection.handleIncomingCloseRequest();
              return;
            }
          case Protocol.CAPABILITIES:
            {
              client.trace("Client received capabilities response");
              while (receiveBuffer.hasRemaining()) {
                final byte type = receiveBuffer.get();
                final int len = receiveBuffer.get() & 0xff;
                final ByteBuffer data = Buffers.slice(receiveBuffer, len);
                switch (type) {
                  case Protocol.CAP_VERSION:
                    {
                      final byte version = data.get();
                      client.tracef(
                          "Client received capability: version %d",
                          Integer.valueOf(version & 0xff));
                      // We only support version zero, so knowing the other side's version is not
                      // useful presently
                      break;
                    }
                  case Protocol.CAP_SASL_MECH:
                    {
                      final String mechName = Buffers.getModifiedUtf8(data);
                      client.tracef("Client received capability: SASL mechanism %s", mechName);
                      if (!failedMechs.contains(mechName)
                          && !disallowedMechs.contains(mechName)
                          && (allowedMechs == null || allowedMechs.contains(mechName))) {
                        client.tracef("SASL mechanism %s added to allowed set", mechName);
                        saslMechs.add(mechName);
                      }
                      break;
                    }
                  case Protocol.CAP_STARTTLS:
                    {
                      client.trace("Client received capability: STARTTLS");
                      starttls = true;
                      break;
                    }
                  default:
                    {
                      client.tracef(
                          "Client received unknown capability %02x", Integer.valueOf(type & 0xff));
                      // unknown, skip it for forward compatibility.
                      break;
                    }
                }
              }
              if (starttls) {
                // only initiate starttls if not forbidden by config
                if (optionMap.get(Options.SSL_STARTTLS, true)) {
                  // Prepare the request message body
                  final Pooled<ByteBuffer> pooledSendBuffer = connection.allocate();
                  final ByteBuffer sendBuffer = pooledSendBuffer.getResource();
                  sendBuffer.put(Protocol.STARTTLS);
                  sendBuffer.flip();
                  connection.setReadListener(new StartTls(serverName));
                  connection.send(pooledSendBuffer);
                  // all set
                  return;
                }
              }

              if (saslMechs.isEmpty()) {
                connection.handleException(
                    new SaslException("No more authentication mechanisms to try"));
                return;
              }
              // OK now send our authentication request
              final OptionMap optionMap = connection.getOptionMap();
              final String userName = optionMap.get(RemotingOptions.AUTHORIZE_ID);
              final Map<String, ?> propertyMap =
                  SaslUtils.createPropertyMap(
                      optionMap, Channels.getOption(channel, Options.SECURE, false));
              final SaslClient saslClient;
              try {
                saslClient =
                    AccessController.doPrivileged(
                        new PrivilegedExceptionAction<SaslClient>() {
                          public SaslClient run() throws SaslException {
                            return Sasl.createSaslClient(
                                saslMechs.toArray(new String[saslMechs.size()]),
                                userName,
                                "remote",
                                serverName,
                                propertyMap,
                                callbackHandler);
                          }
                        },
                        accessControlContext);
              } catch (PrivilegedActionException e) {
                final SaslException se = (SaslException) e.getCause();
                connection.handleException(se);
                return;
              }
              final String mechanismName = saslClient.getMechanismName();
              client.tracef("Client initiating authentication using mechanism %s", mechanismName);
              // Prepare the request message body
              final Pooled<ByteBuffer> pooledSendBuffer = connection.allocate();
              final ByteBuffer sendBuffer = pooledSendBuffer.getResource();
              sendBuffer.put(Protocol.AUTH_REQUEST);
              Buffers.putModifiedUtf8(sendBuffer, mechanismName);
              sendBuffer.flip();
              connection.send(pooledSendBuffer);
              connection.setReadListener(new Authentication(saslClient, serverName));
              return;
            }
          default:
            {
              client.unknownProtocolId(msgType);
              connection.handleException(client.invalidMessage(connection));
              return;
            }
        }
      } catch (BufferUnderflowException e) {
        connection.handleException(client.invalidMessage(connection));
        return;
      } catch (BufferOverflowException e) {
        connection.handleException(client.invalidMessage(connection));
        return;
      } finally {
        pooledReceiveBuffer.free();
      }
    }