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); }
/** * 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); }
/** * 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); } } }); }
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; }
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(); }
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); } }); } } }
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(); } }