/* * Copyright 2014 Red Hat, Inc. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Apache License v2.0 which accompanies this distribution. * * The Eclipse Public License is available at * http://www.eclipse.org/legal/epl-v10.html * * The Apache License v2.0 is available at * http://www.opensource.org/licenses/apache2.0.php * * You may elect to redistribute this code under either of these licenses. */ package io.vertx.test.core; import io.netty.util.internal.logging.InternalLoggerFactory; import io.vertx.core.AbstractVerticle; import io.vertx.core.AsyncResult; import io.vertx.core.Context; import io.vertx.core.DeploymentOptions; import io.vertx.core.Future; import io.vertx.core.Handler; import io.vertx.core.Vertx; import io.vertx.core.VertxOptions; import io.vertx.core.buffer.Buffer; import io.vertx.core.eventbus.Message; import io.vertx.core.eventbus.MessageConsumer; import io.vertx.core.http.ClientAuth; import io.vertx.core.impl.ConcurrentHashSet; import io.vertx.core.impl.ContextImpl; import io.vertx.core.impl.EventLoopContext; import io.vertx.core.impl.VertxInternal; import io.vertx.core.impl.WorkerContext; import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonObject; import io.vertx.core.logging.Logger; import io.vertx.core.logging.LoggerFactory; import io.vertx.core.net.JdkSSLEngineOptions; import io.vertx.core.net.JksOptions; import io.vertx.core.net.NetClient; import io.vertx.core.net.NetClientOptions; import io.vertx.core.net.NetServer; import io.vertx.core.net.NetServerOptions; import io.vertx.core.net.NetSocket; import io.vertx.core.net.NetworkOptions; import io.vertx.core.net.OpenSSLEngineOptions; import io.vertx.core.net.PemKeyCertOptions; import io.vertx.core.net.PemTrustOptions; import io.vertx.core.net.PfxOptions; import io.vertx.core.net.ProxyOptions; import io.vertx.core.net.ProxyType; import io.vertx.core.net.SSLEngineOptions; import io.vertx.core.net.SelfSignedCertificate; import io.vertx.core.net.SocketAddress; import io.vertx.core.net.impl.SocketAddressImpl; import io.vertx.core.streams.ReadStream; import io.vertx.test.core.tls.Cert; import io.vertx.test.core.tls.Trust; import io.vertx.test.netty.TestLoggerFactory; import org.junit.Assume; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import javax.net.ssl.SSLPeerUnverifiedException; import javax.security.cert.X509Certificate; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.OutputStreamWriter; import java.net.InetAddress; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Random; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import static io.vertx.test.core.TestUtils.*; /** * @author <a href="http://tfox.org">Tim Fox</a> */ public class NetTest extends VertxTestBase { private static final Logger log = LoggerFactory.getLogger(NetTest.class); private NetServer server; private NetClient client; private TestProxyBase proxy; @Rule public TemporaryFolder testFolder = new TemporaryFolder(); public void setUp() throws Exception { super.setUp(); client = vertx.createNetClient(new NetClientOptions().setConnectTimeout(1000)); server = vertx.createNetServer(new NetServerOptions().setPort(1234).setHost("localhost")); } @Override protected VertxOptions getOptions() { VertxOptions options = super.getOptions(); options.getAddressResolverOptions().setHostsValue(Buffer.buffer("" + "127.0.0.1 localhost\n" + "127.0.0.1 host1\n" + "127.0.0.1 host2.com\n" + "127.0.0.1 example.com")); return options; } protected void awaitClose(NetServer server) throws InterruptedException { CountDownLatch latch = new CountDownLatch(1); server.close((asyncResult) -> { latch.countDown(); }); awaitLatch(latch); } protected void tearDown() throws Exception { if (client != null) { client.close(); } if (server != null) { awaitClose(server); } if (proxy != null) { proxy.stop(); } super.tearDown(); } @Test public void testClientOptions() { NetClientOptions options = new NetClientOptions(); assertEquals(NetworkOptions.DEFAULT_SEND_BUFFER_SIZE, options.getSendBufferSize()); int rand = TestUtils.randomPositiveInt(); assertEquals(options, options.setSendBufferSize(rand)); assertEquals(rand, options.getSendBufferSize()); assertIllegalArgumentException(() -> options.setSendBufferSize(0)); assertIllegalArgumentException(() -> options.setSendBufferSize(-123)); assertEquals(NetworkOptions.DEFAULT_RECEIVE_BUFFER_SIZE, options.getReceiveBufferSize()); rand = TestUtils.randomPositiveInt(); assertEquals(options, options.setReceiveBufferSize(rand)); assertEquals(rand, options.getReceiveBufferSize()); assertIllegalArgumentException(() -> options.setReceiveBufferSize(0)); assertIllegalArgumentException(() -> options.setReceiveBufferSize(-123)); assertTrue(options.isReuseAddress()); assertEquals(options, options.setReuseAddress(false)); assertFalse(options.isReuseAddress()); assertEquals(NetworkOptions.DEFAULT_TRAFFIC_CLASS, options.getTrafficClass()); rand = 23; assertEquals(options, options.setTrafficClass(rand)); assertEquals(rand, options.getTrafficClass()); assertIllegalArgumentException(() -> options.setTrafficClass(-2)); assertIllegalArgumentException(() -> options.setTrafficClass(256)); assertTrue(options.isTcpNoDelay()); assertEquals(options, options.setTcpNoDelay(false)); assertFalse(options.isTcpNoDelay()); boolean tcpKeepAlive = false; assertEquals(tcpKeepAlive, options.isTcpKeepAlive()); assertEquals(options, options.setTcpKeepAlive(!tcpKeepAlive)); assertEquals(!tcpKeepAlive, options.isTcpKeepAlive()); int soLinger = -1; assertEquals(soLinger, options.getSoLinger()); rand = TestUtils.randomPositiveInt(); assertEquals(options, options.setSoLinger(rand)); assertEquals(rand, options.getSoLinger()); assertIllegalArgumentException(() -> options.setSoLinger(-2)); assertFalse(options.isUsePooledBuffers()); assertEquals(options, options.setUsePooledBuffers(true)); assertTrue(options.isUsePooledBuffers()); rand = TestUtils.randomPositiveInt(); assertEquals(0, options.getIdleTimeout()); assertEquals(options, options.setIdleTimeout(rand)); assertEquals(rand, options.getIdleTimeout()); assertFalse(options.isSsl()); assertEquals(options, options.setSsl(true)); assertTrue(options.isSsl()); assertNull(options.getKeyCertOptions()); JksOptions keyStoreOptions = new JksOptions().setPath(TestUtils.randomAlphaString(100)).setPassword(TestUtils.randomAlphaString(100)); assertEquals(options, options.setKeyStoreOptions(keyStoreOptions)); assertEquals(keyStoreOptions, options.getKeyCertOptions()); assertNull(options.getTrustOptions()); JksOptions trustStoreOptions = new JksOptions().setPath(TestUtils.randomAlphaString(100)).setPassword(TestUtils.randomAlphaString(100)); assertEquals(options, options.setTrustStoreOptions(trustStoreOptions)); assertEquals(trustStoreOptions, options.getTrustOptions()); assertFalse(options.isTrustAll()); assertEquals(options, options.setTrustAll(true)); assertTrue(options.isTrustAll()); String randomAlphaString = TestUtils.randomAlphaString(10); assertTrue(options.getHostnameVerificationAlgorithm().isEmpty()); assertEquals(options, options.setHostnameVerificationAlgorithm(randomAlphaString)); assertEquals(randomAlphaString, options.getHostnameVerificationAlgorithm()); assertEquals(0, options.getReconnectAttempts()); assertIllegalArgumentException(() -> options.setReconnectAttempts(-2)); rand = TestUtils.randomPositiveInt(); assertEquals(options, options.setReconnectAttempts(rand)); assertEquals(rand, options.getReconnectAttempts()); assertEquals(1000, options.getReconnectInterval()); assertIllegalArgumentException(() -> options.setReconnectInterval(0)); rand = TestUtils.randomPositiveInt(); assertEquals(options, options.setReconnectInterval(rand)); assertEquals(rand, options.getReconnectInterval()); assertTrue(options.getEnabledCipherSuites().isEmpty()); assertEquals(options, options.addEnabledCipherSuite("foo")); assertEquals(options, options.addEnabledCipherSuite("bar")); assertNotNull(options.getEnabledCipherSuites()); assertTrue(options.getEnabledCipherSuites().contains("foo")); assertTrue(options.getEnabledCipherSuites().contains("bar")); assertEquals(false, options.isUseAlpn()); assertEquals(options, options.setUseAlpn(true)); assertEquals(true, options.isUseAlpn()); assertNull(options.getSslEngineOptions()); assertEquals(options, options.setSslEngineOptions(new JdkSSLEngineOptions())); assertTrue(options.getSslEngineOptions() instanceof JdkSSLEngineOptions); testComplete(); } @Test public void testServerOptions() { NetServerOptions options = new NetServerOptions(); assertEquals(NetworkOptions.DEFAULT_SEND_BUFFER_SIZE, options.getSendBufferSize()); int rand = TestUtils.randomPositiveInt(); assertEquals(options, options.setSendBufferSize(rand)); assertEquals(rand, options.getSendBufferSize()); assertIllegalArgumentException(() -> options.setSendBufferSize(0)); assertIllegalArgumentException(() -> options.setSendBufferSize(-123)); assertEquals(NetworkOptions.DEFAULT_RECEIVE_BUFFER_SIZE, options.getReceiveBufferSize()); rand = TestUtils.randomPositiveInt(); assertEquals(options, options.setReceiveBufferSize(rand)); assertEquals(rand, options.getReceiveBufferSize()); assertIllegalArgumentException(() -> options.setReceiveBufferSize(0)); assertIllegalArgumentException(() -> options.setReceiveBufferSize(-123)); assertTrue(options.isReuseAddress()); assertEquals(options, options.setReuseAddress(false)); assertFalse(options.isReuseAddress()); assertEquals(NetworkOptions.DEFAULT_TRAFFIC_CLASS, options.getTrafficClass()); rand = 23; assertEquals(options, options.setTrafficClass(rand)); assertEquals(rand, options.getTrafficClass()); assertIllegalArgumentException(() -> options.setTrafficClass(-2)); assertIllegalArgumentException(() -> options.setTrafficClass(256)); assertTrue(options.isTcpNoDelay()); assertEquals(options, options.setTcpNoDelay(false)); assertFalse(options.isTcpNoDelay()); boolean tcpKeepAlive = false; assertEquals(tcpKeepAlive, options.isTcpKeepAlive()); assertEquals(options, options.setTcpKeepAlive(!tcpKeepAlive)); assertEquals(!tcpKeepAlive, options.isTcpKeepAlive()); int soLinger = -1; assertEquals(soLinger, options.getSoLinger()); rand = TestUtils.randomPositiveInt(); assertEquals(options, options.setSoLinger(rand)); assertEquals(rand, options.getSoLinger()); assertIllegalArgumentException(() -> options.setSoLinger(-2)); assertFalse(options.isUsePooledBuffers()); assertEquals(options, options.setUsePooledBuffers(true)); assertTrue(options.isUsePooledBuffers()); rand = TestUtils.randomPositiveInt(); assertEquals(0, options.getIdleTimeout()); assertEquals(options, options.setIdleTimeout(rand)); assertEquals(rand, options.getIdleTimeout()); assertIllegalArgumentException(() -> options.setIdleTimeout(-1)); assertFalse(options.isSsl()); assertEquals(options, options.setSsl(true)); assertTrue(options.isSsl()); assertNull(options.getKeyCertOptions()); JksOptions keyStoreOptions = new JksOptions().setPath(TestUtils.randomAlphaString(100)).setPassword(TestUtils.randomAlphaString(100)); assertEquals(options, options.setKeyStoreOptions(keyStoreOptions)); assertEquals(keyStoreOptions, options.getKeyCertOptions()); assertNull(options.getTrustOptions()); JksOptions trustStoreOptions = new JksOptions().setPath(TestUtils.randomAlphaString(100)).setPassword(TestUtils.randomAlphaString(100)); assertEquals(options, options.setTrustStoreOptions(trustStoreOptions)); assertEquals(trustStoreOptions, options.getTrustOptions()); assertEquals(-1, options.getAcceptBacklog()); rand = TestUtils.randomPositiveInt(); assertEquals(options, options.setAcceptBacklog(rand)); assertEquals(rand, options.getAcceptBacklog()); assertEquals(0, options.getPort()); assertEquals(options, options.setPort(1234)); assertEquals(1234, options.getPort()); assertIllegalArgumentException(() -> options.setPort(-1)); assertIllegalArgumentException(() -> options.setPort(65536)); assertEquals("0.0.0.0", options.getHost()); String randString = TestUtils.randomUnicodeString(100); assertEquals(options, options.setHost(randString)); assertEquals(randString, options.getHost()); assertTrue(options.getEnabledCipherSuites().isEmpty()); assertEquals(options, options.addEnabledCipherSuite("foo")); assertEquals(options, options.addEnabledCipherSuite("bar")); assertNotNull(options.getEnabledCipherSuites()); assertTrue(options.getEnabledCipherSuites().contains("foo")); assertTrue(options.getEnabledCipherSuites().contains("bar")); assertEquals(false, options.isUseAlpn()); assertEquals(options, options.setUseAlpn(true)); assertEquals(true, options.isUseAlpn()); assertNull(options.getSslEngineOptions()); assertEquals(options, options.setSslEngineOptions(new JdkSSLEngineOptions())); assertTrue(options.getSslEngineOptions() instanceof JdkSSLEngineOptions); assertFalse(options.isSni()); assertEquals(options, options.setSni(true)); assertTrue(options.isSni()); testComplete(); } @Test public void testCopyClientOptions() { NetClientOptions options = new NetClientOptions(); int sendBufferSize = TestUtils.randomPositiveInt(); int receiverBufferSize = TestUtils.randomPortInt(); Random rand = new Random(); boolean reuseAddress = rand.nextBoolean(); int trafficClass = TestUtils.randomByte() + 128; boolean tcpNoDelay = rand.nextBoolean(); boolean tcpKeepAlive = rand.nextBoolean(); int soLinger = TestUtils.randomPositiveInt(); boolean usePooledBuffers = rand.nextBoolean(); int idleTimeout = TestUtils.randomPositiveInt(); boolean ssl = rand.nextBoolean(); String hostnameVerificationAlgorithm = TestUtils.randomAlphaString(10); JksOptions keyStoreOptions = new JksOptions(); String ksPassword = TestUtils.randomAlphaString(100); keyStoreOptions.setPassword(ksPassword); JksOptions trustStoreOptions = new JksOptions(); String tsPassword = TestUtils.randomAlphaString(100); trustStoreOptions.setPassword(tsPassword); String enabledCipher = TestUtils.randomAlphaString(100); int connectTimeout = TestUtils.randomPositiveInt(); boolean trustAll = rand.nextBoolean(); String crlPath = TestUtils.randomUnicodeString(100); Buffer crlValue = TestUtils.randomBuffer(100); int reconnectAttempts = TestUtils.randomPositiveInt(); long reconnectInterval = TestUtils.randomPositiveInt(); boolean useAlpn = TestUtils.randomBoolean(); boolean openSslSessionCacheEnabled = rand.nextBoolean(); SSLEngineOptions sslEngine = TestUtils.randomBoolean() ? new JdkSSLEngineOptions() : new OpenSSLEngineOptions(); options.setSendBufferSize(sendBufferSize); options.setReceiveBufferSize(receiverBufferSize); options.setReuseAddress(reuseAddress); options.setTrafficClass(trafficClass); options.setSsl(ssl); options.setTcpNoDelay(tcpNoDelay); options.setTcpKeepAlive(tcpKeepAlive); options.setSoLinger(soLinger); options.setUsePooledBuffers(usePooledBuffers); options.setIdleTimeout(idleTimeout); options.setKeyStoreOptions(keyStoreOptions); options.setTrustStoreOptions(trustStoreOptions); options.addEnabledCipherSuite(enabledCipher); options.setConnectTimeout(connectTimeout); options.setTrustAll(trustAll); options.addCrlPath(crlPath); options.addCrlValue(crlValue); options.setReconnectAttempts(reconnectAttempts); options.setReconnectInterval(reconnectInterval); options.setUseAlpn(useAlpn); options.setSslEngineOptions(sslEngine); options.setHostnameVerificationAlgorithm(hostnameVerificationAlgorithm); NetClientOptions copy = new NetClientOptions(options); assertEquals(sendBufferSize, copy.getSendBufferSize()); assertEquals(receiverBufferSize, copy.getReceiveBufferSize()); assertEquals(reuseAddress, copy.isReuseAddress()); assertEquals(trafficClass, copy.getTrafficClass()); assertEquals(tcpNoDelay, copy.isTcpNoDelay()); assertEquals(tcpKeepAlive, copy.isTcpKeepAlive()); assertEquals(soLinger, copy.getSoLinger()); assertEquals(usePooledBuffers, copy.isUsePooledBuffers()); assertEquals(idleTimeout, copy.getIdleTimeout()); assertEquals(ssl, copy.isSsl()); assertNotSame(keyStoreOptions, copy.getKeyCertOptions()); assertEquals(ksPassword, ((JksOptions) copy.getKeyCertOptions()).getPassword()); assertNotSame(trustStoreOptions, copy.getTrustOptions()); assertEquals(tsPassword, ((JksOptions)copy.getTrustOptions()).getPassword()); assertEquals(1, copy.getEnabledCipherSuites().size()); assertTrue(copy.getEnabledCipherSuites().contains(enabledCipher)); assertEquals(connectTimeout, copy.getConnectTimeout()); assertEquals(trustAll, copy.isTrustAll()); assertEquals(1, copy.getCrlPaths().size()); assertEquals(crlPath, copy.getCrlPaths().get(0)); assertEquals(1, copy.getCrlValues().size()); assertEquals(crlValue, copy.getCrlValues().get(0)); assertEquals(reconnectAttempts, copy.getReconnectAttempts()); assertEquals(reconnectInterval, copy.getReconnectInterval()); assertEquals(useAlpn, copy.isUseAlpn()); assertEquals(sslEngine, copy.getSslEngineOptions()); assertEquals(hostnameVerificationAlgorithm, copy.getHostnameVerificationAlgorithm()); } @Test public void testDefaultClientOptionsJson() { NetClientOptions def = new NetClientOptions(); NetClientOptions json = new NetClientOptions(new JsonObject()); assertEquals(def.getReconnectAttempts(), json.getReconnectAttempts()); assertEquals(def.getReconnectInterval(), json.getReconnectInterval()); assertEquals(def.isTrustAll(), json.isTrustAll()); assertEquals(def.getCrlPaths(), json.getCrlPaths()); assertEquals(def.getCrlValues(), json.getCrlValues()); assertEquals(def.getConnectTimeout(), json.getConnectTimeout()); assertEquals(def.isTcpNoDelay(), json.isTcpNoDelay()); assertEquals(def.isTcpKeepAlive(), json.isTcpKeepAlive()); assertEquals(def.getSoLinger(), json.getSoLinger()); assertEquals(def.isUsePooledBuffers(), json.isUsePooledBuffers()); assertEquals(def.isSsl(), json.isSsl()); assertEquals(def.isUseAlpn(), json.isUseAlpn()); assertEquals(def.getSslEngineOptions(), json.getSslEngineOptions()); assertEquals(def.getHostnameVerificationAlgorithm(), json.getHostnameVerificationAlgorithm()); } @Test public void testClientOptionsJson() { int sendBufferSize = TestUtils.randomPositiveInt(); int receiverBufferSize = TestUtils.randomPortInt(); Random rand = new Random(); boolean reuseAddress = rand.nextBoolean(); int trafficClass = TestUtils.randomByte() + 128; boolean tcpNoDelay = rand.nextBoolean(); boolean tcpKeepAlive = rand.nextBoolean(); int soLinger = TestUtils.randomPositiveInt(); boolean usePooledBuffers = rand.nextBoolean(); int idleTimeout = TestUtils.randomPositiveInt(); boolean ssl = rand.nextBoolean(); JksOptions keyStoreOptions = new JksOptions(); String ksPassword = TestUtils.randomAlphaString(100); keyStoreOptions.setPassword(ksPassword); String ksPath = TestUtils.randomAlphaString(100); keyStoreOptions.setPath(ksPath); JksOptions trustStoreOptions = new JksOptions(); String tsPassword = TestUtils.randomAlphaString(100); trustStoreOptions.setPassword(tsPassword); String tsPath = TestUtils.randomAlphaString(100); trustStoreOptions.setPath(tsPath); String enabledCipher = TestUtils.randomAlphaString(100); int connectTimeout = TestUtils.randomPositiveInt(); boolean trustAll = rand.nextBoolean(); String crlPath = TestUtils.randomUnicodeString(100); int reconnectAttempts = TestUtils.randomPositiveInt(); long reconnectInterval = TestUtils.randomPositiveInt(); boolean useAlpn = TestUtils.randomBoolean(); String hostnameVerificationAlgorithm = TestUtils.randomAlphaString(10); String sslEngine = TestUtils.randomBoolean() ? "jdkSslEngineOptions" : "openSslEngineOptions"; boolean openSslSessionCacheEnabled = rand.nextBoolean(); JsonObject json = new JsonObject(); json.put("sendBufferSize", sendBufferSize) .put("receiveBufferSize", receiverBufferSize) .put("reuseAddress", reuseAddress) .put("trafficClass", trafficClass) .put("tcpNoDelay", tcpNoDelay) .put("tcpKeepAlive", tcpKeepAlive) .put("soLinger", soLinger) .put("usePooledBuffers", usePooledBuffers) .put("idleTimeout", idleTimeout) .put("ssl", ssl) .put("enabledCipherSuites", new JsonArray().add(enabledCipher)) .put("connectTimeout", connectTimeout) .put("trustAll", trustAll) .put("crlPaths", new JsonArray().add(crlPath)) .put("keyStoreOptions", new JsonObject().put("password", ksPassword).put("path", ksPath)) .put("trustStoreOptions", new JsonObject().put("password", tsPassword).put("path", tsPath)) .put("reconnectAttempts", reconnectAttempts) .put("reconnectInterval", reconnectInterval) .put("useAlpn", useAlpn) .put(sslEngine, new JsonObject()) .put("hostnameVerificationAlgorithm", hostnameVerificationAlgorithm) .put("openSslSessionCacheEnabled", openSslSessionCacheEnabled); NetClientOptions options = new NetClientOptions(json); assertEquals(sendBufferSize, options.getSendBufferSize()); assertEquals(receiverBufferSize, options.getReceiveBufferSize()); assertEquals(reuseAddress, options.isReuseAddress()); assertEquals(trafficClass, options.getTrafficClass()); assertEquals(tcpKeepAlive, options.isTcpKeepAlive()); assertEquals(tcpNoDelay, options.isTcpNoDelay()); assertEquals(soLinger, options.getSoLinger()); assertEquals(usePooledBuffers, options.isUsePooledBuffers()); assertEquals(idleTimeout, options.getIdleTimeout()); assertEquals(ssl, options.isSsl()); assertNotSame(keyStoreOptions, options.getKeyCertOptions()); assertEquals(ksPassword, ((JksOptions) options.getKeyCertOptions()).getPassword()); assertEquals(ksPath, ((JksOptions) options.getKeyCertOptions()).getPath()); assertNotSame(trustStoreOptions, options.getTrustOptions()); assertEquals(tsPassword, ((JksOptions) options.getTrustOptions()).getPassword()); assertEquals(tsPath, ((JksOptions) options.getTrustOptions()).getPath()); assertEquals(1, options.getEnabledCipherSuites().size()); assertTrue(options.getEnabledCipherSuites().contains(enabledCipher)); assertEquals(connectTimeout, options.getConnectTimeout()); assertEquals(trustAll, options.isTrustAll()); assertEquals(1, options.getCrlPaths().size()); assertEquals(crlPath, options.getCrlPaths().get(0)); assertEquals(reconnectAttempts, options.getReconnectAttempts()); assertEquals(reconnectInterval, options.getReconnectInterval()); assertEquals(useAlpn, options.isUseAlpn()); switch (sslEngine) { case "jdkSslEngineOptions": assertTrue(options.getSslEngineOptions() instanceof JdkSSLEngineOptions); break; case "openSslEngineOptions": assertTrue(options.getSslEngineOptions() instanceof OpenSSLEngineOptions); break; default: fail(); break; } assertEquals(hostnameVerificationAlgorithm, options.getHostnameVerificationAlgorithm()); // Test other keystore/truststore types json.remove("keyStoreOptions"); json.remove("trustStoreOptions"); json.put("pfxKeyCertOptions", new JsonObject().put("password", ksPassword)) .put("pfxTrustOptions", new JsonObject().put("password", tsPassword)); options = new NetClientOptions(json); assertTrue(options.getTrustOptions() instanceof PfxOptions); assertTrue(options.getKeyCertOptions() instanceof PfxOptions); json.remove("pfxKeyCertOptions"); json.remove("pfxTrustOptions"); json.put("pemKeyCertOptions", new JsonObject()) .put("pemTrustOptions", new JsonObject()); options = new NetClientOptions(json); assertTrue(options.getTrustOptions() instanceof PemTrustOptions); assertTrue(options.getKeyCertOptions() instanceof PemKeyCertOptions); } @Test public void testCopyServerOptions() { NetServerOptions options = new NetServerOptions(); int sendBufferSize = TestUtils.randomPositiveInt(); int receiverBufferSize = TestUtils.randomPortInt(); Random rand = new Random(); boolean reuseAddress = rand.nextBoolean(); int trafficClass = TestUtils.randomByte() + 128; boolean tcpNoDelay = rand.nextBoolean(); boolean tcpKeepAlive = rand.nextBoolean(); int soLinger = TestUtils.randomPositiveInt(); boolean usePooledBuffers = rand.nextBoolean(); int idleTimeout = TestUtils.randomPositiveInt(); boolean ssl = rand.nextBoolean(); JksOptions keyStoreOptions = new JksOptions(); String ksPassword = TestUtils.randomAlphaString(100); keyStoreOptions.setPassword(ksPassword); JksOptions trustStoreOptions = new JksOptions(); String tsPassword = TestUtils.randomAlphaString(100); trustStoreOptions.setPassword(tsPassword); String enabledCipher = TestUtils.randomAlphaString(100); String crlPath = TestUtils.randomUnicodeString(100); Buffer crlValue = TestUtils.randomBuffer(100); int port = 1234; String host = TestUtils.randomAlphaString(100); int acceptBacklog = TestUtils.randomPortInt(); boolean useAlpn = TestUtils.randomBoolean(); boolean openSslSessionCacheEnabled = rand.nextBoolean(); SSLEngineOptions sslEngine = TestUtils.randomBoolean() ? new JdkSSLEngineOptions() : new OpenSSLEngineOptions(); boolean sni = TestUtils.randomBoolean(); options.setSendBufferSize(sendBufferSize); options.setReceiveBufferSize(receiverBufferSize); options.setReuseAddress(reuseAddress); options.setTrafficClass(trafficClass); options.setTcpNoDelay(tcpNoDelay); options.setTcpKeepAlive(tcpKeepAlive); options.setSoLinger(soLinger); options.setUsePooledBuffers(usePooledBuffers); options.setIdleTimeout(idleTimeout); options.setSsl(ssl); options.setKeyStoreOptions(keyStoreOptions); options.setTrustStoreOptions(trustStoreOptions); options.addEnabledCipherSuite(enabledCipher); options.addCrlPath(crlPath); options.addCrlValue(crlValue); options.setPort(port); options.setHost(host); options.setAcceptBacklog(acceptBacklog); options.setUseAlpn(useAlpn); options.setSslEngineOptions(sslEngine); options.setSni(sni); NetServerOptions copy = new NetServerOptions(options); assertEquals(sendBufferSize, copy.getSendBufferSize()); assertEquals(receiverBufferSize, copy.getReceiveBufferSize()); assertEquals(reuseAddress, copy.isReuseAddress()); assertEquals(trafficClass, copy.getTrafficClass()); assertEquals(tcpNoDelay, copy.isTcpNoDelay()); assertEquals(tcpKeepAlive, copy.isTcpKeepAlive()); assertEquals(soLinger, copy.getSoLinger()); assertEquals(usePooledBuffers, copy.isUsePooledBuffers()); assertEquals(idleTimeout, copy.getIdleTimeout()); assertEquals(ssl, copy.isSsl()); assertNotSame(keyStoreOptions, copy.getKeyCertOptions()); assertEquals(ksPassword, ((JksOptions) copy.getKeyCertOptions()).getPassword()); assertNotSame(trustStoreOptions, copy.getTrustOptions()); assertEquals(tsPassword, ((JksOptions)copy.getTrustOptions()).getPassword()); assertEquals(1, copy.getEnabledCipherSuites().size()); assertTrue(copy.getEnabledCipherSuites().contains(enabledCipher)); assertEquals(1, copy.getCrlPaths().size()); assertEquals(crlPath, copy.getCrlPaths().get(0)); assertEquals(1, copy.getCrlValues().size()); assertEquals(crlValue, copy.getCrlValues().get(0)); assertEquals(port, copy.getPort()); assertEquals(host, copy.getHost()); assertEquals(acceptBacklog, copy.getAcceptBacklog()); assertEquals(useAlpn, copy.isUseAlpn()); assertEquals(sslEngine, copy.getSslEngineOptions()); assertEquals(sni, copy.isSni()); } @Test public void testDefaultServerOptionsJson() { NetServerOptions def = new NetServerOptions(); NetServerOptions json = new NetServerOptions(new JsonObject()); assertEquals(def.isClientAuthRequired(), json.isClientAuthRequired()); assertEquals(def.getCrlPaths(), json.getCrlPaths()); assertEquals(def.getCrlValues(), json.getCrlValues()); assertEquals(def.getAcceptBacklog(), json.getAcceptBacklog()); assertEquals(def.getPort(), json.getPort()); assertEquals(def.getHost(), json.getHost()); assertEquals(def.isClientAuthRequired(), json.isClientAuthRequired()); assertEquals(def.getCrlPaths(), json.getCrlPaths()); assertEquals(def.getCrlValues(), json.getCrlValues()); assertEquals(def.getAcceptBacklog(), json.getAcceptBacklog()); assertEquals(def.getPort(), json.getPort()); assertEquals(def.getHost(), json.getHost()); assertEquals(def.isTcpNoDelay(), json.isTcpNoDelay()); assertEquals(def.isTcpKeepAlive(), json.isTcpKeepAlive()); assertEquals(def.getSoLinger(), json.getSoLinger()); assertEquals(def.isUsePooledBuffers(), json.isUsePooledBuffers()); assertEquals(def.isSsl(), json.isSsl()); assertEquals(def.isUseAlpn(), json.isUseAlpn()); assertEquals(def.getSslEngineOptions(), json.getSslEngineOptions()); assertEquals(def.isSni(), json.isSni()); } @Test public void testServerOptionsJson() { int sendBufferSize = TestUtils.randomPositiveInt(); int receiverBufferSize = TestUtils.randomPortInt(); Random rand = new Random(); boolean reuseAddress = rand.nextBoolean(); int trafficClass = TestUtils.randomByte() + 128; boolean tcpNoDelay = rand.nextBoolean(); boolean tcpKeepAlive = rand.nextBoolean(); int soLinger = TestUtils.randomPositiveInt(); boolean usePooledBuffers = rand.nextBoolean(); int idleTimeout = TestUtils.randomPositiveInt(); boolean ssl = rand.nextBoolean(); JksOptions keyStoreOptions = new JksOptions(); String ksPassword = TestUtils.randomAlphaString(100); keyStoreOptions.setPassword(ksPassword); String ksPath = TestUtils.randomAlphaString(100); keyStoreOptions.setPath(ksPath); JksOptions trustStoreOptions = new JksOptions(); String tsPassword = TestUtils.randomAlphaString(100); trustStoreOptions.setPassword(tsPassword); String tsPath = TestUtils.randomAlphaString(100); trustStoreOptions.setPath(tsPath); String enabledCipher = TestUtils.randomAlphaString(100); String crlPath = TestUtils.randomUnicodeString(100); int port = 1234; String host = TestUtils.randomAlphaString(100); int acceptBacklog = TestUtils.randomPortInt(); boolean useAlpn = TestUtils.randomBoolean(); boolean openSslSessionCacheEnabled = rand.nextBoolean(); String sslEngine = TestUtils.randomBoolean() ? "jdkSslEngineOptions" : "openSslEngineOptions"; boolean sni = TestUtils.randomBoolean(); JsonObject json = new JsonObject(); json.put("sendBufferSize", sendBufferSize) .put("receiveBufferSize", receiverBufferSize) .put("reuseAddress", reuseAddress) .put("trafficClass", trafficClass) .put("tcpNoDelay", tcpNoDelay) .put("tcpKeepAlive", tcpKeepAlive) .put("soLinger", soLinger) .put("usePooledBuffers", usePooledBuffers) .put("idleTimeout", idleTimeout) .put("ssl", ssl) .put("enabledCipherSuites", new JsonArray().add(enabledCipher)) .put("crlPaths", new JsonArray().add(crlPath)) .put("keyStoreOptions", new JsonObject().put("password", ksPassword).put("path", ksPath)) .put("trustStoreOptions", new JsonObject().put("password", tsPassword).put("path", tsPath)) .put("port", port) .put("host", host) .put("acceptBacklog", acceptBacklog) .put("useAlpn", useAlpn) .put(sslEngine, new JsonObject()) .put("openSslSessionCacheEnabled", openSslSessionCacheEnabled) .put("sni", sni); NetServerOptions options = new NetServerOptions(json); assertEquals(sendBufferSize, options.getSendBufferSize()); assertEquals(receiverBufferSize, options.getReceiveBufferSize()); assertEquals(reuseAddress, options.isReuseAddress()); assertEquals(trafficClass, options.getTrafficClass()); assertEquals(tcpKeepAlive, options.isTcpKeepAlive()); assertEquals(tcpNoDelay, options.isTcpNoDelay()); assertEquals(soLinger, options.getSoLinger()); assertEquals(usePooledBuffers, options.isUsePooledBuffers()); assertEquals(idleTimeout, options.getIdleTimeout()); assertEquals(ssl, options.isSsl()); assertNotSame(keyStoreOptions, options.getKeyCertOptions()); assertEquals(ksPassword, ((JksOptions) options.getKeyCertOptions()).getPassword()); assertEquals(ksPath, ((JksOptions) options.getKeyCertOptions()).getPath()); assertNotSame(trustStoreOptions, options.getTrustOptions()); assertEquals(tsPassword, ((JksOptions) options.getTrustOptions()).getPassword()); assertEquals(tsPath, ((JksOptions) options.getTrustOptions()).getPath()); assertEquals(1, options.getEnabledCipherSuites().size()); assertTrue(options.getEnabledCipherSuites().contains(enabledCipher)); assertEquals(1, options.getCrlPaths().size()); assertEquals(crlPath, options.getCrlPaths().get(0)); assertEquals(port, options.getPort()); assertEquals(host, options.getHost()); assertEquals(acceptBacklog, options.getAcceptBacklog()); assertEquals(useAlpn, options.isUseAlpn()); switch (sslEngine) { case "jdkSslEngineOptions": assertTrue(options.getSslEngineOptions() instanceof JdkSSLEngineOptions); break; case "openSslEngineOptions": assertTrue(options.getSslEngineOptions() instanceof OpenSSLEngineOptions); break; default: fail(); break; } assertEquals(sni, options.isSni()); // Test other keystore/truststore types json.remove("keyStoreOptions"); json.remove("trustStoreOptions"); json.put("pfxKeyCertOptions", new JsonObject().put("password", ksPassword)) .put("pfxTrustOptions", new JsonObject().put("password", tsPassword)); options = new NetServerOptions(json); assertTrue(options.getTrustOptions() instanceof PfxOptions); assertTrue(options.getKeyCertOptions() instanceof PfxOptions); json.remove("pfxKeyCertOptions"); json.remove("pfxTrustOptions"); json.put("pemKeyCertOptions", new JsonObject()) .put("pemTrustOptions", new JsonObject()); options = new NetServerOptions(json); assertTrue(options.getTrustOptions() instanceof PemTrustOptions); assertTrue(options.getKeyCertOptions() instanceof PemKeyCertOptions); } @Test public void testSocketAddress() throws Exception { assertNullPointerException(() -> new SocketAddressImpl(0, null)); assertIllegalArgumentException(() -> new SocketAddressImpl(0, "")); assertIllegalArgumentException(() -> new SocketAddressImpl(-1, "someHost")); assertIllegalArgumentException(() -> new SocketAddressImpl(65536, "someHost")); } @Test public void testEchoBytes() { Buffer sent = TestUtils.randomBuffer(100); testEcho(sock -> sock.write(sent), buff -> assertEquals(sent, buff), sent.length()); } @Test public void testEchoString() { String sent = TestUtils.randomUnicodeString(100); Buffer buffSent = Buffer.buffer(sent); testEcho(sock -> sock.write(sent), buff -> assertEquals(buffSent, buff), buffSent.length()); } @Test public void testEchoStringUTF8() { testEchoStringWithEncoding("UTF-8"); } @Test public void testEchoStringUTF16() { testEchoStringWithEncoding("UTF-16"); } void testEchoStringWithEncoding(String encoding) { String sent = TestUtils.randomUnicodeString(100); Buffer buffSent = Buffer.buffer(sent, encoding); testEcho(sock -> sock.write(sent, encoding), buff -> assertEquals(buffSent, buff), buffSent.length()); } void testEcho(Consumer<NetSocket> writer, Consumer<Buffer> dataChecker, int length) { Handler<AsyncResult<NetSocket>> clientHandler = (asyncResult) -> { if (asyncResult.succeeded()) { NetSocket sock = asyncResult.result(); Buffer buff = Buffer.buffer(); sock.handler((buffer) -> { buff.appendBuffer(buffer); if (buff.length() == length) { dataChecker.accept(buff); testComplete(); } if (buff.length() > length) { fail("Too many bytes received"); } }); writer.accept(sock); } else { fail("failed to connect"); } }; startEchoServer(s -> client.connect(1234, "localhost", clientHandler)); await(); } void startEchoServer(Handler<AsyncResult<NetServer>> listenHandler) { Handler<NetSocket> serverHandler = socket -> socket.handler(socket::write); server.connectHandler(serverHandler).listen(listenHandler); } @Test public void testConnectLocalHost() { connect(1234, "localhost"); } void connect(int port, String host) { startEchoServer(s -> { final int numConnections = 100; final AtomicInteger connCount = new AtomicInteger(0); for (int i = 0; i < numConnections; i++) { Handler<AsyncResult<NetSocket>> handler = res -> { if (res.succeeded()) { res.result().close(); if (connCount.incrementAndGet() == numConnections) { testComplete(); } } }; client.connect(port, host, handler); } }); await(); } @Test public void testConnectInvalidPort() { assertIllegalArgumentException(() -> client.connect(-1, "localhost", res -> {})); assertIllegalArgumentException(() -> client.connect(65536, "localhost", res -> {})); client.connect(9998, "localhost", res -> { assertTrue(res.failed()); assertFalse(res.succeeded()); assertNotNull(res.cause()); testComplete(); }); await(); } @Test public void testConnectInvalidHost() { assertNullPointerException(() -> client.connect(80, null, res -> {})); client.connect(1234, "127.0.0.2", res -> { assertTrue(res.failed()); assertFalse(res.succeeded()); assertNotNull(res.cause()); testComplete(); }); await(); } @Test public void testConnectInvalidConnectHandler() throws Exception { assertNullPointerException(() -> client.connect(80, "localhost", null)); } @Test public void testListenInvalidPort() { /* Port 80 is free to use by any application on Windows, so this test fails. */ Assume.assumeFalse(System.getProperty("os.name").startsWith("Windows")); server.close(); server = vertx.createNetServer(new NetServerOptions().setPort(80)); server.connectHandler((netSocket) -> { }).listen(ar -> { assertTrue(ar.failed()); assertFalse(ar.succeeded()); assertNotNull(ar.cause()); testComplete(); }); await(); } @Test public void testListenInvalidHost() { server.close(); server = vertx.createNetServer(new NetServerOptions().setPort(1234).setHost("uhqwduhqwudhqwuidhqwiudhqwudqwiuhd")); server.connectHandler(netSocket -> { }).listen(ar -> { assertTrue(ar.failed()); assertFalse(ar.succeeded()); assertNotNull(ar.cause()); testComplete(); }); await(); } @Test public void testListenOnWildcardPort() { server.close(); server = vertx.createNetServer(new NetServerOptions().setPort(0)); server.connectHandler((netSocket) -> { }).listen(ar -> { assertFalse(ar.failed()); assertTrue(ar.succeeded()); assertNull(ar.cause()); assertTrue(server.actualPort() > 1024); assertEquals(server, ar.result()); testComplete(); }); await(); } @Test public void testClientCloseHandlersCloseFromClient() { startEchoServer(s -> clientCloseHandlers(true)); await(); } @Test public void testClientCloseHandlersCloseFromServer() { server.connectHandler((netSocket) -> netSocket.close()).listen((s) -> clientCloseHandlers(false)); await(); } void clientCloseHandlers(boolean closeFromClient) { client.connect(1234, "localhost", ar -> { AtomicInteger counter = new AtomicInteger(0); ar.result().endHandler(v -> assertEquals(1, counter.incrementAndGet())); ar.result().closeHandler(v -> { assertEquals(2, counter.incrementAndGet()); testComplete(); }); if (closeFromClient) { ar.result().close(); } }); } @Test public void testServerCloseHandlersCloseFromClient() { serverCloseHandlers(false, s -> client.connect(1234, "localhost", ar -> ar.result().close())); await(); } @Test public void testServerCloseHandlersCloseFromServer() { serverCloseHandlers(true, s -> client.connect(1234, "localhost", ar -> { })); await(); } void serverCloseHandlers(boolean closeFromServer, Handler<AsyncResult<NetServer>> listenHandler) { server.connectHandler((sock) -> { AtomicInteger counter = new AtomicInteger(0); sock.endHandler(v -> assertEquals(1, counter.incrementAndGet())); sock.closeHandler(v -> { assertEquals(2, counter.incrementAndGet()); testComplete(); }); if (closeFromServer) { sock.close(); } }).listen(listenHandler); } @Test public void testClientDrainHandler() { pausingServer((s) -> { client.connect(1234, "localhost", ar -> { NetSocket sock = ar.result(); assertFalse(sock.writeQueueFull()); sock.setWriteQueueMaxSize(1000); Buffer buff = TestUtils.randomBuffer(10000); vertx.setPeriodic(1, id -> { sock.write(buff.copy()); if (sock.writeQueueFull()) { vertx.cancelTimer(id); sock.drainHandler(v -> { assertFalse(sock.writeQueueFull()); testComplete(); }); // Tell the server to resume vertx.eventBus().send("server_resume", ""); } }); }); }); await(); } void pausingServer(Handler<AsyncResult<NetServer>> listenHandler) { server.connectHandler(sock -> { sock.pause(); Handler<Message<Buffer>> resumeHandler = (m) -> sock.resume(); MessageConsumer reg = vertx.eventBus().<Buffer>consumer("server_resume").handler(resumeHandler); sock.closeHandler(v -> reg.unregister()); }).listen(listenHandler); } @Test public void testServerDrainHandler() { drainingServer(s -> { client.connect(1234, "localhost", ar -> { NetSocket sock = ar.result(); sock.pause(); setHandlers(sock); sock.handler(buf -> { }); }); }); await(); } void setHandlers(NetSocket sock) { Handler<Message<Buffer>> resumeHandler = m -> sock.resume(); MessageConsumer reg = vertx.eventBus().<Buffer>consumer("client_resume").handler(resumeHandler); sock.closeHandler(v -> reg.unregister()); } void drainingServer(Handler<AsyncResult<NetServer>> listenHandler) { server.connectHandler(sock -> { assertFalse(sock.writeQueueFull()); sock.setWriteQueueMaxSize(1000); Buffer buff = TestUtils.randomBuffer(10000); //Send data until the buffer is full vertx.setPeriodic(1, id -> { sock.write(buff.copy()); if (sock.writeQueueFull()) { vertx.cancelTimer(id); sock.drainHandler(v -> { assertFalse(sock.writeQueueFull()); // End test after a short delay to give the client some time to read the data vertx.setTimer(100, id2 -> testComplete()); }); // Tell the client to resume vertx.eventBus().send("client_resume", ""); } }); }).listen(listenHandler); } @Test public void testReconnectAttemptsInfinite() { reconnectAttempts(-1); } @Test public void testReconnectAttemptsMany() { reconnectAttempts(100000); } void reconnectAttempts(int attempts) { client.close(); client = vertx.createNetClient(new NetClientOptions().setReconnectAttempts(attempts).setReconnectInterval(10)); //The server delays starting for a a few seconds, but it should still connect client.connect(1234, "localhost", (res) -> { assertTrue(res.succeeded()); assertFalse(res.failed()); testComplete(); }); // Start the server after a delay vertx.setTimer(2000, id -> startEchoServer(s -> { })); await(); } @Test public void testReconnectAttemptsNotEnough() { client.close(); client = vertx.createNetClient(new NetClientOptions().setReconnectAttempts(100).setReconnectInterval(10)); client.connect(1234, "localhost", (res) -> { assertFalse(res.succeeded()); assertTrue(res.failed()); testComplete(); }); await(); } @Test public void testServerIdleTimeout() { server.close(); server = vertx.createNetServer(new NetServerOptions().setPort(1234).setHost("localhost").setIdleTimeout(1)); server.connectHandler(s -> {}).listen(ar -> { assertTrue(ar.succeeded()); client.connect(1234, "localhost", res -> { assertTrue(res.succeeded()); NetSocket socket = res.result(); socket.closeHandler(v -> testComplete()); }); }); await(); } @Test public void testClientIdleTimeout() { client.close(); client = vertx.createNetClient(new NetClientOptions().setIdleTimeout(1)); server.connectHandler(s -> { }).listen(ar -> { assertTrue(ar.succeeded()); client.connect(1234, "localhost", res -> { assertTrue(res.succeeded()); NetSocket socket = res.result(); socket.closeHandler(v -> testComplete()); }); }); await(); } @Test // StartTLS public void testStartTLSClientTrustAll() throws Exception { testTLS(Cert.NONE, Trust.NONE, Cert.SERVER_JKS, Trust.NONE, false, true, true, true); } @Test // Client trusts all server certs public void testTLSClientTrustAll() throws Exception { testTLS(Cert.NONE, Trust.NONE, Cert.SERVER_JKS, Trust.NONE, false, true, true, false); } @Test // Server specifies cert that the client trusts (not trust all) public void testTLSClientTrustServerCert() throws Exception { testTLS(Cert.NONE, Trust.SERVER_JKS, Cert.SERVER_JKS, Trust.NONE, false, false, true, false); } @Test // Server specifies cert that the client doesn't trust public void testTLSClientUntrustedServer() throws Exception { testTLS(Cert.NONE, Trust.NONE, Cert.SERVER_JKS, Trust.NONE, false, false, false, false); } @Test //Client specifies cert even though it's not required public void testTLSClientCertNotRequired() throws Exception { testTLS(Cert.CLIENT_JKS, Trust.SERVER_JKS, Cert.SERVER_JKS, Trust.CLIENT_JKS, false, false, true, false); } @Test //Client specifies cert and it's not required public void testTLSClientCertRequired() throws Exception { testTLS(Cert.CLIENT_JKS, Trust.SERVER_JKS, Cert.SERVER_JKS, Trust.CLIENT_JKS, true, false, true, false); } @Test //Client doesn't specify cert but it's required public void testTLSClientCertRequiredNoClientCert() throws Exception { testTLS(Cert.NONE, Trust.SERVER_JKS, Cert.SERVER_JKS, Trust.CLIENT_JKS, true, false, false, false); } @Test //Client specifies cert but it's not trusted public void testTLSClientCertClientNotTrusted() throws Exception { testTLS(Cert.NONE, Trust.SERVER_JKS, Cert.SERVER_JKS, Trust.NONE, true, false, false, false); } @Test // Specify some cipher suites public void testTLSCipherSuites() throws Exception { testTLS(Cert.NONE, Trust.NONE, Cert.SERVER_JKS, Trust.NONE, false, true, true, false, ENABLED_CIPHER_SUITES); } @Test // Specify some bogus protocol public void testInvalidTlsProtocolVersion() throws Exception { testTLS(Cert.NONE, Trust.NONE, Cert.SERVER_JKS, Trust.NONE, false, true, false, false, new String[0], new String[]{"TLSv1.999"}); } @Test // Specify a valid protocol public void testSpecificTlsProtocolVersion() throws Exception { testTLS(Cert.NONE, Trust.NONE, Cert.SERVER_JKS, Trust.NONE, false, true, true, false, new String[0], new String[]{"TLSv1.2"}); } @Test // SNI without server name should use the first keystore entry public void testSniWithoutServerNameUsesTheFirstKeyStoreEntry1() throws Exception { TLSTest test = new TLSTest() .clientTrust(Trust.SERVER_JKS) .serverCert(Cert.SNI_JKS).sni(true); test.run(true); await(); assertEquals("localhost", cnOf(test.clientPeerCert())); } @Test // SNI without server name should use the first keystore entry public void testSniWithoutServerNameUsesTheFirstKeyStoreEntry2() throws Exception { TLSTest test = new TLSTest() .clientTrust(Trust.SNI_JKS_HOST1) .serverCert(Cert.SNI_JKS).sni(true); test.run(false); await(); } @Test public void testSniImplicitServerName() throws Exception { TLSTest test = new TLSTest() .clientTrust(Trust.SNI_JKS_HOST2) .host("host2.com") .serverCert(Cert.SNI_JKS).sni(true); test.run(true); await(); assertEquals("host2.com", cnOf(test.clientPeerCert())); assertEquals("host2.com", test.indicatedServerName); } @Test public void testSniImplicitServerNameDisabledForShortname1() throws Exception { TLSTest test = new TLSTest() .clientTrust(Trust.SNI_JKS_HOST1) .host("host1") .serverCert(Cert.SNI_JKS).sni(true); test.run(false); await(); } @Test public void testSniImplicitServerNameDisabledForShortname2() throws Exception { TLSTest test = new TLSTest() .clientTrust(Trust.SERVER_JKS) .host("host1") .serverCert(Cert.SNI_JKS).sni(true); test.run(true); await(); assertEquals("localhost", cnOf(test.clientPeerCert())); } @Test public void testSniForceShortname() throws Exception { TLSTest test = new TLSTest() .clientTrust(Trust.SNI_JKS_HOST1) .host("host1") .serverName("host1") .serverCert(Cert.SNI_JKS).sni(true); test.run(true); await(); assertEquals("host1", cnOf(test.clientPeerCert())); } @Test public void testSniOverrideServerName() throws Exception { TLSTest test = new TLSTest() .clientTrust(Trust.SNI_JKS_HOST2) .host("example.com") .serverName("host2.com") .serverCert(Cert.SNI_JKS).sni(true); test.run(true); await(); assertEquals("host2.com", cnOf(test.clientPeerCert())); } @Test // SNI present an unknown server public void testSniWithUnknownServer1() throws Exception { TLSTest test = new TLSTest() .clientTrust(Trust.SERVER_JKS) .serverCert(Cert.SNI_JKS).sni(true).serverName("unknown"); test.run(true); await(); assertEquals("localhost", cnOf(test.clientPeerCert())); } @Test // SNI present an unknown server public void testSniWithUnknownServer2() throws Exception { TLSTest test = new TLSTest() .clientTrust(Trust.SNI_JKS_HOST2) .serverCert(Cert.SNI_JKS).sni(true).serverName("unknown"); test.run(false); await(); } @Test // SNI returns the certificate for the indicated server name public void testSniWithServerNameStartTLS() throws Exception { TLSTest test = new TLSTest() .clientTrust(Trust.SNI_JKS_HOST1) .startTLS(true) .serverCert(Cert.SNI_JKS).sni(true).serverName("host1"); test.run(true); await(); assertEquals("host1", cnOf(test.clientPeerCert())); } void testTLS(Cert<?> clientCert, Trust<?> clientTrust, Cert<?> serverCert, Trust<?> serverTrust, boolean requireClientAuth, boolean clientTrustAll, boolean shouldPass, boolean startTLS) throws Exception { testTLS(clientCert, clientTrust, serverCert, serverTrust, requireClientAuth, clientTrustAll, shouldPass, startTLS, new String[0], new String[0]); } void testTLS(Cert<?> clientCert, Trust<?> clientTrust, Cert<?> serverCert, Trust<?> serverTrust, boolean requireClientAuth, boolean clientTrustAll, boolean shouldPass, boolean startTLS, String[] enabledCipherSuites) throws Exception { testTLS(clientCert, clientTrust, serverCert, serverTrust, requireClientAuth, clientTrustAll, shouldPass, startTLS, enabledCipherSuites, new String[0]); } void testTLS(Cert<?> clientCert, Trust<?> clientTrust, Cert<?> serverCert, Trust<?> serverTrust, boolean requireClientAuth, boolean clientTrustAll, boolean shouldPass, boolean startTLS, String[] enabledCipherSuites, String[] enabledSecureTransportProtocols) throws Exception { TLSTest test = new TLSTest() .clientCert(clientCert) .clientTrust(clientTrust) .serverCert(serverCert) .serverTrust(serverTrust) .requireClientAuth(requireClientAuth) .clientTrustAll(clientTrustAll) .startTLS(startTLS) .enabledCipherSuites(enabledCipherSuites) .enabledSecureTransportProtocols(enabledSecureTransportProtocols); test.run(shouldPass); await(); } class TLSTest { Cert<?> clientCert = Cert.NONE; Trust<?> clientTrust = Trust.NONE; Cert<?> serverCert = Cert.NONE; Trust<?> serverTrust = Trust.NONE; boolean requireClientAuth; boolean clientTrustAll; boolean startTLS; String[] enabledCipherSuites = new String[0]; String[] enabledSecureTransportProtocols = new String[0]; boolean sni; String host = "localhost"; String serverName; X509Certificate clientPeerCert; String indicatedServerName; public TLSTest clientCert(Cert<?> clientCert) { this.clientCert = clientCert; return this; } public TLSTest clientTrust(Trust<?> clientTrust) { this.clientTrust = clientTrust; return this; } public TLSTest serverCert(Cert<?> serverCert) { this.serverCert = serverCert; return this; } public TLSTest serverTrust(Trust<?> serverTrust) { this.serverTrust = serverTrust; return this; } public TLSTest requireClientAuth(boolean requireClientAuth) { this.requireClientAuth = requireClientAuth; return this; } public TLSTest clientTrustAll(boolean clientTrustAll) { this.clientTrustAll = clientTrustAll; return this; } public TLSTest startTLS(boolean startTLS) { this.startTLS = startTLS; return this; } public TLSTest enabledCipherSuites(String[] enabledCipherSuites) { this.enabledCipherSuites = enabledCipherSuites; return this; } public TLSTest enabledSecureTransportProtocols(String[] enabledSecureTransportProtocols) { this.enabledSecureTransportProtocols = enabledSecureTransportProtocols; return this; } public TLSTest host(String host) { this.host = host; return this; } public TLSTest serverName(String serverName) { this.serverName = serverName; return this; } public TLSTest sni(boolean sni) { this.sni = sni; return this; } public X509Certificate clientPeerCert() { return clientPeerCert; } void run(boolean shouldPass) { server.close(); NetServerOptions options = new NetServerOptions(); if (!startTLS) { options.setSsl(true); } options.setTrustOptions(serverTrust.get()); options.setKeyCertOptions(serverCert.get()); if (requireClientAuth) { options.setClientAuth(ClientAuth.REQUIRED); } for (String suite: enabledCipherSuites) { options.addEnabledCipherSuite(suite); } for (String protocol : enabledSecureTransportProtocols) { options.addEnabledSecureTransportProtocol(protocol); } options.setSni(sni); Consumer<NetSocket> certificateChainChecker = socket -> { try { X509Certificate[] certs = socket.peerCertificateChain(); if (clientCert != Cert.NONE) { assertNotNull(certs); assertEquals(1, certs.length); } else { assertNull(certs); } } catch (SSLPeerUnverifiedException e) { assertTrue(clientTrust.get() != Trust.NONE || clientTrustAll); } }; options.setPort(4043); server = vertx.createNetServer(options); Handler<NetSocket> serverHandler = socket -> { indicatedServerName = socket.indicatedServerName(); if (socket.isSsl()) { certificateChainChecker.accept(socket); } AtomicBoolean upgradedServer = new AtomicBoolean(); AtomicInteger upgradedServerCount = new AtomicInteger(); socket.handler(buff -> { socket.write(buff); // echo the data if (startTLS) { if (upgradedServer.compareAndSet(false, true)) { indicatedServerName = socket.indicatedServerName(); assertFalse(socket.isSsl()); socket.upgradeToSsl(v -> { certificateChainChecker.accept(socket); upgradedServerCount.incrementAndGet(); assertTrue(socket.isSsl()); }); } else { assertTrue(socket.isSsl()); assertEquals(1, upgradedServerCount.get()); } } else { assertTrue(socket.isSsl()); } }); }; server.connectHandler(serverHandler).listen(ar -> { client.close(); NetClientOptions clientOptions = new NetClientOptions(); if (!startTLS) { clientOptions.setSsl(true); } if (clientTrustAll) { clientOptions.setTrustAll(true); } clientOptions.setTrustOptions(clientTrust.get()); clientOptions.setKeyCertOptions(clientCert.get()); for (String suite: enabledCipherSuites) { clientOptions.addEnabledCipherSuite(suite); } for (String protocol : enabledSecureTransportProtocols) { clientOptions.addEnabledSecureTransportProtocol(protocol); } client = vertx.createNetClient(clientOptions); client.connect(4043, host, serverName, ar2 -> { if (ar2.succeeded()) { if (!shouldPass) { fail("Should not connect"); return; } final int numChunks = 100; final int chunkSize = 100; final List<Buffer> toSend = new ArrayList<>(); final Buffer expected = Buffer.buffer(); for (int i = 0; i< numChunks;i++) { Buffer chunk = TestUtils.randomBuffer(chunkSize); toSend.add(chunk); expected.appendBuffer(chunk); } final Buffer received = Buffer.buffer(); final NetSocket socket = ar2.result(); if (socket.isSsl()) { try { clientPeerCert = socket.peerCertificateChain()[0]; } catch (SSLPeerUnverifiedException ignore) { } } final AtomicBoolean upgradedClient = new AtomicBoolean(); socket.handler(buffer -> { received.appendBuffer(buffer); if (received.length() == expected.length()) { assertEquals(expected, received); testComplete(); } if (startTLS && !upgradedClient.get()) { upgradedClient.set(true); assertFalse(socket.isSsl()); Handler<Void> handler = v -> { assertTrue(socket.isSsl()); try { clientPeerCert = socket.peerCertificateChain()[0]; } catch (SSLPeerUnverifiedException ignore) { } // Now send the rest for (int i = 1; i < numChunks; i++) { socket.write(toSend.get(i)); } }; if (serverName != null) { socket.upgradeToSsl(serverName, handler); } else { socket.upgradeToSsl(handler); } } else { assertTrue(socket.isSsl()); } }); //Now send some data int numToSend = startTLS ? 1 : numChunks; for (int i = 0; i < numToSend; i++) { socket.write(toSend.get(i)); } } else { if (shouldPass) { fail("Should not fail to connect"); } else { testComplete(); } } }); }); } } @Test // Need to: // sudo sysctl -w net.core.somaxconn=10000 // sudo sysctl -w net.ipv4.tcp_max_syn_backlog=10000 // To get this to reliably pass with a lot of connections. public void testSharedServersRoundRobin() throws Exception { int numServers = 5; int numConnections = numServers * 20; List<NetServer> servers = new ArrayList<>(); Set<NetServer> connectedServers = new ConcurrentHashSet<>(); Map<NetServer, Integer> connectCount = new ConcurrentHashMap<>(); CountDownLatch latchListen = new CountDownLatch(numServers); CountDownLatch latchConns = new CountDownLatch(numConnections); for (int i = 0; i < numServers; i++) { NetServer theServer = vertx.createNetServer(new NetServerOptions().setHost("localhost").setPort(1234)); servers.add(theServer); theServer.connectHandler(sock -> { connectedServers.add(theServer); Integer cnt = connectCount.get(theServer); int icnt = cnt == null ? 0 : cnt; icnt++; connectCount.put(theServer, icnt); latchConns.countDown(); }).listen(ar -> { if (ar.succeeded()) { latchListen.countDown(); } else { fail("Failed to bind server"); } }); } assertTrue(latchListen.await(10, TimeUnit.SECONDS)); // Create a bunch of connections client.close(); client = vertx.createNetClient(new NetClientOptions()); CountDownLatch latchClient = new CountDownLatch(numConnections); for (int i = 0; i < numConnections; i++) { client.connect(1234, "localhost", res -> { if (res.succeeded()) { latchClient.countDown(); } else { res.cause().printStackTrace(); fail("Failed to connect"); } }); } assertTrue(latchClient.await(10, TimeUnit.SECONDS)); assertTrue(latchConns.await(10, TimeUnit.SECONDS)); assertEquals(numServers, connectedServers.size()); for (NetServer server : servers) { assertTrue(connectedServers.contains(server)); } assertEquals(numServers, connectCount.size()); for (int cnt : connectCount.values()) { assertEquals(numConnections / numServers, cnt); } CountDownLatch closeLatch = new CountDownLatch(numServers); for (NetServer server : servers) { server.close(ar -> { assertTrue(ar.succeeded()); closeLatch.countDown(); }); } assertTrue(closeLatch.await(10, TimeUnit.SECONDS)); testComplete(); } @Test public void testSharedServersRoundRobinWithOtherServerRunningOnDifferentPort() throws Exception { CountDownLatch latch = new CountDownLatch(1); // Have a server running on a different port to make sure it doesn't interact server.close(); server = vertx.createNetServer(new NetServerOptions().setPort(4321)); server.connectHandler(sock -> { fail("Should not connect"); }).listen(ar2 -> { if (ar2.succeeded()) { latch.countDown(); } else { fail("Failed to bind server"); } }); awaitLatch(latch); testSharedServersRoundRobin(); } @Test public void testSharedServersRoundRobinButFirstStartAndStopServer() throws Exception { // Start and stop a server on the same port/host before hand to make sure it doesn't interact server.close(); CountDownLatch latch = new CountDownLatch(1); server = vertx.createNetServer(new NetServerOptions().setPort(1234)); server.connectHandler(sock -> { fail("Should not connect"); }).listen(ar -> { if (ar.succeeded()) { latch.countDown(); } else { fail("Failed to bind server"); } }); awaitLatch(latch); CountDownLatch closeLatch = new CountDownLatch(1); server.close(ar -> { assertTrue(ar.succeeded()); closeLatch.countDown(); }); assertTrue(closeLatch.await(10, TimeUnit.SECONDS)); testSharedServersRoundRobin(); } @Test // This tests using NetSocket.writeHandlerID (on the server side) // Send some data and make sure it is fanned out to all connections public void testFanout() throws Exception { CountDownLatch latch = new CountDownLatch(1); Set<String> connections = new ConcurrentHashSet<>(); server.connectHandler(socket -> { connections.add(socket.writeHandlerID()); socket.handler(buffer -> { for (String actorID : connections) { vertx.eventBus().publish(actorID, buffer); } }); socket.closeHandler(v -> { connections.remove(socket.writeHandlerID()); }); }); server.listen(ar -> { assertTrue(ar.succeeded()); latch.countDown(); }); awaitLatch(latch); int numConnections = 10; CountDownLatch connectLatch = new CountDownLatch(numConnections); CountDownLatch receivedLatch = new CountDownLatch(numConnections); for (int i = 0; i < numConnections; i++) { client.connect(1234, "localhost", res -> { connectLatch.countDown(); res.result().handler(data -> { receivedLatch.countDown(); }); }); } assertTrue(connectLatch.await(10, TimeUnit.SECONDS)); // Send some data client.connect(1234, "localhost", res -> { res.result().write("foo"); }); assertTrue(receivedLatch.await(10, TimeUnit.SECONDS)); testComplete(); } @Test public void testRemoteAddress() throws Exception { server.connectHandler(socket -> { SocketAddress addr = socket.remoteAddress(); assertEquals("127.0.0.1", addr.host()); }).listen(ar -> { assertTrue(ar.succeeded()); vertx.createNetClient(new NetClientOptions()).connect(1234, "localhost", result -> { NetSocket socket = result.result(); SocketAddress addr = socket.remoteAddress(); assertEquals("127.0.0.1", addr.host()); assertEquals(addr.port(), 1234); testComplete(); }); }); await(); } @Test public void testWriteSameBufferMoreThanOnce() throws Exception { server.connectHandler(socket -> { Buffer received = Buffer.buffer(); socket.handler(buff -> { received.appendBuffer(buff); if (received.toString().equals("foofoo")) { testComplete(); } }); }).listen(ar -> { assertTrue(ar.succeeded()); client.connect(1234, "localhost", result -> { NetSocket socket = result.result(); Buffer buff = Buffer.buffer("foo"); socket.write(buff); socket.write(buff); }); }); await(); } @Test public void sendFileClientToServer() throws Exception { File fDir = testFolder.newFolder(); String content = TestUtils.randomUnicodeString(10000); File file = setupFile(fDir.toString(), "some-file.txt", content); Buffer expected = Buffer.buffer(content); Buffer received = Buffer.buffer(); server.connectHandler(sock -> { sock.handler(buff -> { received.appendBuffer(buff); if (received.length() == expected.length()) { assertEquals(expected, received); testComplete(); } }); // Send some data to the client to trigger the sendfile sock.write("foo"); }); server.listen(ar -> { assertTrue(ar.succeeded()); client.connect(1234, "localhost", ar2 -> { assertTrue(ar2.succeeded()); NetSocket sock = ar2.result(); sock.handler(buf -> { sock.sendFile(file.getAbsolutePath()); }); }); }); await(); } @Test public void sendFileServerToClient() throws Exception { File fDir = testFolder.newFolder(); String content = TestUtils.randomUnicodeString(10000); File file = setupFile(fDir.toString(), "some-file.txt", content); Buffer expected = Buffer.buffer(content); Buffer received = Buffer.buffer(); server.connectHandler(sock -> { sock.handler(buf -> { sock.sendFile(file.getAbsolutePath()); }); }); server.listen(ar -> { assertTrue(ar.succeeded()); client.connect(1234, "localhost", ar2 -> { assertTrue(ar2.succeeded()); NetSocket sock = ar2.result(); sock.handler(buff -> { received.appendBuffer(buff); if (received.length() == expected.length()) { assertEquals(expected, received); testComplete(); } }); sock.write("foo"); }); }); await(); } @Test public void testSendFileDirectory() throws Exception { File fDir = testFolder.newFolder(); server.connectHandler(socket -> { SocketAddress addr = socket.remoteAddress(); assertEquals("127.0.0.1", addr.host()); }).listen(ar -> { assertTrue(ar.succeeded()); client.connect(1234, "localhost", result -> { assertTrue(result.succeeded()); NetSocket socket = result.result(); try { socket.sendFile(fDir.getAbsolutePath().toString()); // should throw exception and never hit the assert fail("Should throw exception"); } catch (IllegalArgumentException e) { testComplete(); } }); }); await(); } @Test public void testServerOptionsCopiedBeforeUse() { server.close(); NetServerOptions options = new NetServerOptions().setPort(1234); NetServer server = vertx.createNetServer(options); // Now change something - but server should still listen at previous port options.setPort(1235); server.connectHandler(sock -> { testComplete(); }); server.listen(ar -> { assertTrue(ar.succeeded()); client.connect(1234, "localhost", ar2 -> { assertTrue(ar2.succeeded()); }); }); await(); } @Test public void testClientOptionsCopiedBeforeUse() { client.close(); NetClientOptions options = new NetClientOptions(); client = vertx.createNetClient(options); options.setSsl(true); // Now change something - but server should ignore this server.connectHandler(sock -> { testComplete(); }); server.listen(ar -> { assertTrue(ar.succeeded()); client.connect(1234, "localhost", ar2 -> { assertTrue(ar2.succeeded()); }); }); await(); } @Test public void testListenWithNoHandler() { try { server.listen(); fail("Should throw exception"); } catch (IllegalStateException e) { // OK } } @Test public void testListenWithNoHandler2() { try { server.listen(ar -> { assertFalse(ar.succeeded()); }); fail("Should throw exception"); } catch (IllegalStateException e) { // OK } } @Test public void testSetHandlerAfterListen() { server.connectHandler(sock -> { }); server.listen(); try { server.connectHandler(sock -> { }); fail("Should throw exception"); } catch (IllegalStateException e) { // OK } } @Test public void testSetHandlerAfterListen2() { server.connectHandler(sock -> { }); server.listen(ar -> { assertTrue(ar.succeeded()); try { server.connectHandler(sock -> { }); fail("Should throw exception"); } catch (IllegalStateException e) { // OK } testComplete(); }); await(); } @Test public void testListenTwice() { server.connectHandler(sock -> { }); server.listen(onSuccess(s -> { try { server.listen(res -> {}); fail("Should throw exception"); } catch (IllegalStateException e) { // OK testComplete(); } catch (Exception e) { fail(e.getMessage()); } })); await(); } @Test public void testListenOnPortNoHandler() { server.connectHandler(NetSocket::close); server.listen(1234, onSuccess(ns -> { client.connect(1234, "localhost", onSuccess(so -> { so.closeHandler(v -> { testComplete(); }); })); })); await(); } @Test public void testListen() { server.connectHandler(NetSocket::close); server.listen(onSuccess(ns -> { client.connect(1234, "localhost", onSuccess(so -> { so.closeHandler(v -> { testComplete(); }); })); })); await(); } @Test public void testListenTwice2() { server.connectHandler(sock -> { }); server.listen(ar -> { assertTrue(ar.succeeded()); try { server.listen(sock -> { }); fail("Should throw exception"); } catch (IllegalStateException e) { // OK } testComplete(); }); await(); } @Test public void testCloseTwice() { client.close(); client.close(); // OK } @Test public void testAttemptConnectAfterClose() { client.close(); try { client.connect(1234, "localhost", ar -> { }); fail("Should throw exception"); } catch (IllegalStateException e) { //OK } } @Test public void testClientMultiThreaded() throws Exception { int numThreads = 10; Thread[] threads = new Thread[numThreads]; CountDownLatch latch = new CountDownLatch(numThreads); server.connectHandler(socket -> { socket.handler(socket::write); }).listen(ar -> { assertTrue(ar.succeeded()); for (int i = 0; i < numThreads; i++) { threads[i] = new Thread() { public void run() { client.connect(1234, "localhost", result -> { assertTrue(result.succeeded()); Buffer buff = TestUtils.randomBuffer(100000); NetSocket sock = result.result(); sock.write(buff); Buffer received = Buffer.buffer(); sock.handler(rec -> { received.appendBuffer(rec); if (received.length() == buff.length()) { assertEquals(buff, received); latch.countDown(); } }); }); } }; threads[i].start(); } }); awaitLatch(latch); for (int i = 0; i < numThreads; i++) { threads[i].join(); } } @Test public void testInVerticle() throws Exception { testInVerticle(false); } private void testInVerticle(boolean worker) throws Exception { client.close(); server.close(); class MyVerticle extends AbstractVerticle { Context ctx; @Override public void start() { ctx = context; if (worker) { assertTrue(ctx instanceof WorkerContext); } else { assertTrue(ctx instanceof EventLoopContext); } Thread thr = Thread.currentThread(); server = vertx.createNetServer(new NetServerOptions().setPort(1234).setHost("localhost")); server.connectHandler(sock -> { sock.handler(buff -> { sock.write(buff); }); assertSame(ctx, context); if (!worker) { assertSame(thr, Thread.currentThread()); } }); server.listen(ar -> { assertTrue(ar.succeeded()); assertSame(ctx, context); if (!worker) { assertSame(thr, Thread.currentThread()); } client = vertx.createNetClient(new NetClientOptions()); client.connect(1234, "localhost", ar2 -> { assertSame(ctx, context); if (!worker) { assertSame(thr, Thread.currentThread()); } assertTrue(ar2.succeeded()); NetSocket sock = ar2.result(); Buffer buff = TestUtils.randomBuffer(10000); sock.write(buff); Buffer brec = Buffer.buffer(); sock.handler(rec -> { assertSame(ctx, context); if (!worker) { assertSame(thr, Thread.currentThread()); } brec.appendBuffer(rec); if (brec.length() == buff.length()) { testComplete(); } }); }); }); } } MyVerticle verticle = new MyVerticle(); vertx.deployVerticle(verticle, new DeploymentOptions().setWorker(worker)); await(); } @Test public void testInMultithreadedWorker() throws Exception { class MyVerticle extends AbstractVerticle { @Override public void start() { try { server = vertx.createNetServer(new NetServerOptions()); fail("Should throw exception"); } catch (IllegalStateException e) { // OK } try { client = vertx.createNetClient(new NetClientOptions()); fail("Should throw exception"); } catch (IllegalStateException e) { // OK } testComplete(); } } MyVerticle verticle = new MyVerticle(); vertx.deployVerticle(verticle, new DeploymentOptions().setWorker(true).setMultiThreaded(true)); await(); } @Test public void testContexts() throws Exception { Set<ContextImpl> contexts = new ConcurrentHashSet<>(); AtomicInteger cnt = new AtomicInteger(); AtomicReference<ContextImpl> serverConnectContext = new AtomicReference<>(); // Server connect handler should always be called with same context server.connectHandler(sock -> { sock.handler(sock::write); ContextImpl serverContext = ((VertxInternal) vertx).getContext(); if (serverConnectContext.get() != null) { assertSame(serverConnectContext.get(), serverContext); } else { serverConnectContext.set(serverContext); } }); CountDownLatch latch = new CountDownLatch(1); AtomicReference<ContextImpl> listenContext = new AtomicReference<>(); server.listen(ar -> { assertTrue(ar.succeeded()); listenContext.set(((VertxInternal) vertx).getContext()); latch.countDown(); }); awaitLatch(latch); CountDownLatch latch2 = new CountDownLatch(1); int numConns = 10; // Each connect should be in its own context for (int i = 0; i < numConns; i++) { client.connect(1234, "localhost", conn -> { contexts.add(((VertxInternal) vertx).getContext()); if (cnt.incrementAndGet() == numConns) { assertEquals(numConns, contexts.size()); latch2.countDown(); } }); } awaitLatch(latch2); // Close should be in own context server.close(ar -> { assertTrue(ar.succeeded()); ContextImpl closeContext = ((VertxInternal) vertx).getContext(); assertFalse(contexts.contains(closeContext)); assertNotSame(serverConnectContext.get(), closeContext); assertFalse(contexts.contains(listenContext.get())); assertSame(serverConnectContext.get(), listenContext.get()); testComplete(); }); server = null; await(); } @Test public void testReadStreamPauseResume() { server.close(); server = vertx.createNetServer(new NetServerOptions().setAcceptBacklog(1).setPort(1234).setHost("localhost")); ReadStream<NetSocket> socketStream = server.connectStream(); AtomicBoolean paused = new AtomicBoolean(); socketStream.handler(so -> { assertTrue(!paused.get()); so.write("hello"); so.close(); }); server.listen(ar -> { assertTrue(ar.succeeded()); paused.set(true); socketStream.pause(); client.connect(1234, "localhost", ar2 -> { assertTrue(ar2.succeeded()); NetSocket so2 = ar2.result(); so2.handler(buffer -> { fail(); }); so2.closeHandler(v -> { paused.set(false); socketStream.resume(); client.connect(1234, "localhost", ar3 -> { assertTrue(ar3.succeeded()); NetSocket so3 = ar3.result(); Buffer buffer = Buffer.buffer(); so3.handler(buffer::appendBuffer); so3.closeHandler(v3 -> { assertEquals("hello", buffer.toString("utf-8")); testComplete(); }); }); }); }); }); await(); } @Test public void testNetSocketStreamCallbackIsAsync() { this.server = vertx.createNetServer(new NetServerOptions()); AtomicInteger done = new AtomicInteger(); ReadStream<NetSocket> stream = server.connectStream(); stream.handler(req -> {}); ThreadLocal<Object> stack = new ThreadLocal<>(); stack.set(true); stream.endHandler(v -> { assertTrue(Vertx.currentContext().isEventLoopContext()); assertNull(stack.get()); if (done.incrementAndGet() == 2) { testComplete(); } }); server.listen(ar -> { assertTrue(Vertx.currentContext().isEventLoopContext()); assertNull(stack.get()); ThreadLocal<Object> stack2 = new ThreadLocal<>(); stack2.set(true); server.close(v -> { assertTrue(Vertx.currentContext().isEventLoopContext()); assertNull(stack2.get()); if (done.incrementAndGet() == 2) { testComplete(); } }); stack2.set(null); }); await(); } @Test public void testMultipleServerClose() { this.server = vertx.createNetServer(new NetServerOptions()); AtomicInteger times = new AtomicInteger(); // We assume the endHandler and the close completion handler are invoked in the same context task ThreadLocal stack = new ThreadLocal(); stack.set(true); server.connectStream().endHandler(v -> { assertNull(stack.get()); assertTrue(Vertx.currentContext().isEventLoopContext()); times.incrementAndGet(); }); server.close(ar1 -> { assertNull(stack.get()); assertTrue(Vertx.currentContext().isEventLoopContext()); server.close(ar2 -> { server.close(ar3 -> { assertEquals(1, times.get()); testComplete(); }); }); }); await(); } @Test public void testInWorker() throws Exception { vertx.deployVerticle(new AbstractVerticle() { @Override public void start() throws Exception { assertTrue(Vertx.currentContext().isWorkerContext()); assertTrue(Context.isOnWorkerThread()); final Context context = Vertx.currentContext(); NetServer server1 = vertx.createNetServer(new NetServerOptions().setHost("localhost").setPort(1234)); server1.connectHandler(conn -> { assertTrue(Vertx.currentContext().isWorkerContext()); assertTrue(Context.isOnWorkerThread()); assertSame(context, Vertx.currentContext()); conn.handler(conn::write); conn.closeHandler(v -> { testComplete(); }); }).listen(onSuccess(s -> { assertTrue(Vertx.currentContext().isWorkerContext()); assertTrue(Context.isOnWorkerThread()); assertSame(context, Vertx.currentContext()); NetClient client = vertx.createNetClient(); client.connect(1234, "localhost", onSuccess(res -> { assertTrue(Vertx.currentContext().isWorkerContext()); assertTrue(Context.isOnWorkerThread()); assertSame(context, Vertx.currentContext()); res.write("foo"); res.handler(buff -> { assertTrue(Vertx.currentContext().isWorkerContext()); assertTrue(Context.isOnWorkerThread()); assertSame(context, Vertx.currentContext()); res.close(); }); })); })); } }, new DeploymentOptions().setWorker(true)); await(); } private File setupFile(String testDir, String fileName, String content) throws Exception { File file = new File(testDir, fileName); if (file.exists()) { file.delete(); } BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8")); out.write(content); out.close(); return file; } @Test public void testServerWorkerMissBufferWhenBufferArriveBeforeConnectCallback() throws Exception { int size = getOptions().getWorkerPoolSize(); List<Context> workers = createWorkers(size + 1); CountDownLatch latch1 = new CountDownLatch(workers.size() - 1); workers.get(0).runOnContext(v -> { NetServer server = vertx.createNetServer(); server.connectHandler(so -> { so.handler(buf -> { assertEquals("hello", buf.toString()); testComplete(); }); }); server.listen(1234, ar -> { assertTrue(ar.succeeded()); // Create a one second worker starvation for (int i = 1; i < workers.size(); i++) { workers.get(i).runOnContext(v2 -> { latch1.countDown(); try { Thread.sleep(1000); } catch (InterruptedException ignore) { } }); } }); }); awaitLatch(latch1); NetClient client = vertx.createNetClient(); client.connect(1234, "localhost", ar -> { assertTrue(ar.succeeded()); NetSocket so = ar.result(); so.write(Buffer.buffer("hello")); }); await(); } @Test public void testClientWorkerMissBufferWhenBufferArriveBeforeConnectCallback() throws Exception { int size = getOptions().getWorkerPoolSize(); List<Context> workers = createWorkers(size + 1); CountDownLatch latch1 = new CountDownLatch(1); CountDownLatch latch2 = new CountDownLatch(size); NetServer server = vertx.createNetServer(); server.connectHandler(so -> { try { awaitLatch(latch2); } catch (InterruptedException e) { fail(e.getMessage()); return; } so.write(Buffer.buffer("hello")); }); server.listen(1234, ar -> { assertTrue(ar.succeeded()); latch1.countDown(); }); awaitLatch(latch1); workers.get(0).runOnContext(v -> { NetClient client = vertx.createNetClient(); client.connect(1234, "localhost", ar -> { assertTrue(ar.succeeded()); NetSocket so = ar.result(); so.handler(buf -> { assertEquals("hello", buf.toString()); testComplete(); }); }); // Create a one second worker starvation for (int i = 1; i < workers.size(); i++) { workers.get(i).runOnContext(v2 -> { latch2.countDown(); try { Thread.sleep(1000); } catch (InterruptedException ignore) { } }); } }); await(); } @Test public void testHostVerificationHttpsNotMatching() { server.close(); NetServerOptions options = new NetServerOptions() .setPort(1234) .setHost("localhost") .setSsl(true) .setKeyStoreOptions(new JksOptions().setPath("tls/mim-server-keystore.jks").setPassword("wibble")); NetServer server = vertx.createNetServer(options); NetClientOptions clientOptions = new NetClientOptions() .setSsl(true) .setTrustAll(true) .setHostnameVerificationAlgorithm("HTTPS"); NetClient client = vertx.createNetClient(clientOptions); server.connectHandler(sock -> { }); server.listen(ar -> { assertTrue(ar.succeeded()); client.connect(1234, "localhost", ar2 -> { //Should not be able to connect assertTrue(ar2.failed()); testComplete(); }); }); await(); } // this test sets HostnameVerification but also trustAll, it fails if hostname is // incorrect but does not verify the certificate validity @Test public void testHostVerificationHttpsMatching() { server.close(); NetServerOptions options = new NetServerOptions() .setPort(1234) .setHost("localhost") .setSsl(true) .setKeyStoreOptions(new JksOptions().setPath("tls/server-keystore.jks").setPassword("wibble")); NetServer server = vertx.createNetServer(options); NetClientOptions clientOptions = new NetClientOptions() .setSsl(true) .setTrustAll(true) .setHostnameVerificationAlgorithm("HTTPS"); NetClient client = vertx.createNetClient(clientOptions); server.connectHandler(sock -> { }); server.listen(ar -> { assertTrue(ar.succeeded()); client.connect(1234, "localhost", ar2 -> { //Should be able to connect assertTrue(ar2.succeeded()); testComplete(); }); }); await(); } @Test public void testNoLogging() throws Exception { TestLoggerFactory factory = testLogging(); assertFalse(factory.hasName("io.netty.handler.logging.LoggingHandler")); } @Test public void testServerLogging() throws Exception { server.close(); server = vertx.createNetServer(new NetServerOptions().setLogActivity(true)); TestLoggerFactory factory = testLogging(); assertTrue(factory.hasName("io.netty.handler.logging.LoggingHandler")); } @Test public void testClientLogging() throws Exception { client.close(); client = vertx.createNetClient(new NetClientOptions().setLogActivity(true)); TestLoggerFactory factory = testLogging(); assertTrue(factory.hasName("io.netty.handler.logging.LoggingHandler")); } private TestLoggerFactory testLogging() throws Exception { InternalLoggerFactory prev = InternalLoggerFactory.getDefaultFactory(); TestLoggerFactory factory = new TestLoggerFactory(); InternalLoggerFactory.setDefaultFactory(factory); try { server.connectHandler(so -> { so.write("fizzbuzz").end(); }); server.listen(1234, "localhost", onSuccess(v1 -> { client.connect(1234, "localhost", onSuccess(so -> { so.closeHandler(v2 -> testComplete()); })); })); await(); } finally { InternalLoggerFactory.setDefaultFactory(prev); } return factory; } /** * test socks5 proxy for accessing arbitrary server port. */ @Test public void testWithSocks5Proxy() { NetClientOptions clientOptions = new NetClientOptions() .setProxyOptions(new ProxyOptions().setType(ProxyType.SOCKS5).setPort(11080)); NetClient client = vertx.createNetClient(clientOptions); server.connectHandler(sock -> { }); proxy = new SocksProxy(null); proxy.start(vertx, v -> { server.listen(ar -> { assertTrue(ar.succeeded()); client.connect(1234, "localhost", ar2 -> { if (ar2.failed()) { log.warn("failed", ar2.cause()); } assertTrue(ar2.succeeded()); // make sure we have gone through the proxy assertEquals("localhost:1234", proxy.getLastUri()); testComplete(); }); }); }); await(); } /** * test socks5 proxy for accessing arbitrary server port with authentication. */ @Test public void testWithSocks5ProxyAuth() { NetClientOptions clientOptions = new NetClientOptions() .setProxyOptions(new ProxyOptions().setType(ProxyType.SOCKS5).setPort(11080) .setUsername("username").setPassword("username")); NetClient client = vertx.createNetClient(clientOptions); server.connectHandler(sock -> { }); proxy = new SocksProxy("username"); proxy.start(vertx, v -> { server.listen(ar -> { assertTrue(ar.succeeded()); client.connect(1234, "localhost", ar2 -> { assertTrue(ar2.succeeded()); testComplete(); }); }); }); await(); } /** * test socks5 proxy when accessing ssl server port with correct cert. */ @Test public void testConnectSSLWithSocks5Proxy() { server.close(); NetServerOptions options = new NetServerOptions() .setPort(1234) .setHost("localhost") .setSsl(true) .setKeyCertOptions(Cert.SERVER_JKS_ROOT_CA.get()); NetServer server = vertx.createNetServer(options); NetClientOptions clientOptions = new NetClientOptions() .setHostnameVerificationAlgorithm("HTTPS") .setSsl(true) .setProxyOptions(new ProxyOptions().setType(ProxyType.SOCKS5).setHost("127.0.0.1").setPort(11080)) .setTrustOptions(Trust.SERVER_JKS_ROOT_CA.get()); NetClient client = vertx.createNetClient(clientOptions); server.connectHandler(sock -> { }); proxy = new SocksProxy(null); proxy.start(vertx, v -> { server.listen(ar -> { assertTrue(ar.succeeded()); client.connect(1234, "localhost", ar2 -> { assertTrue(ar2.succeeded()); testComplete(); }); }); }); await(); } /** * test socks5 proxy for accessing ssl server port with upgradeToSsl. * https://github.com/eclipse/vert.x/issues/1602 */ @Test public void testUpgradeSSLWithSocks5Proxy() { server.close(); NetServerOptions options = new NetServerOptions() .setPort(1234) .setHost("localhost") .setSsl(true) .setKeyCertOptions(Cert.SERVER_JKS_ROOT_CA.get()); NetServer server = vertx.createNetServer(options); NetClientOptions clientOptions = new NetClientOptions() .setHostnameVerificationAlgorithm("HTTPS") .setProxyOptions(new ProxyOptions().setType(ProxyType.SOCKS5).setHost("127.0.0.1").setPort(11080)) .setTrustOptions(Trust.SERVER_JKS_ROOT_CA.get()); NetClient client = vertx.createNetClient(clientOptions); server.connectHandler(sock -> { }); proxy = new SocksProxy(null); proxy.start(vertx, v -> { server.listen(ar -> { assertTrue(ar.succeeded()); client.connect(1234, "localhost", ar2 -> { assertTrue(ar2.succeeded()); NetSocket ns = ar2.result(); ns.exceptionHandler(th -> { fail(th); }); ns.upgradeToSsl(v2 -> { // failure would occur before upgradeToSsl completes testComplete(); }); }); }); }); await(); } /** * test http connect proxy for accessing a arbitrary server port * note that this may not work with a "real" proxy since there are usually access rules defined * that limit the target host and ports (e.g. connecting to localhost or to port 25 may not be allowed) */ @Test public void testWithHttpConnectProxy() { NetClientOptions clientOptions = new NetClientOptions() .setProxyOptions(new ProxyOptions().setType(ProxyType.HTTP).setPort(13128)); NetClient client = vertx.createNetClient(clientOptions); server.connectHandler(sock -> { }); proxy = new HttpProxy(null); proxy.start(vertx, v -> { server.listen(ar -> { assertTrue(ar.succeeded()); client.connect(1234, "localhost", ar2 -> { if (ar2.failed()) { log.warn("failed", ar2.cause()); } assertTrue(ar2.succeeded()); // make sure we have gone through the proxy assertEquals("localhost:1234", proxy.getLastUri()); testComplete(); }); }); }); await(); } /** * test socks4a proxy for accessing arbitrary server port. */ @Test public void testWithSocks4aProxy() { NetClientOptions clientOptions = new NetClientOptions() .setProxyOptions(new ProxyOptions().setType(ProxyType.SOCKS4).setPort(11080)); NetClient client = vertx.createNetClient(clientOptions); server.connectHandler(sock -> { }); proxy = new Socks4Proxy(null); proxy.start(vertx, v -> { server.listen(ar -> { assertTrue(ar.succeeded()); client.connect(1234, "localhost", ar2 -> { if (ar2.failed()) { log.warn("failed", ar2.cause()); } assertTrue(ar2.succeeded()); // make sure we have gone through the proxy assertEquals("localhost:1234", proxy.getLastUri()); testComplete(); }); }); }); await(); } /** * test socks4a proxy for accessing arbitrary server port using username auth. */ @Test public void testWithSocks4aProxyAuth() { NetClientOptions clientOptions = new NetClientOptions() .setProxyOptions(new ProxyOptions().setType(ProxyType.SOCKS4).setPort(11080) .setUsername("username")); NetClient client = vertx.createNetClient(clientOptions); server.connectHandler(sock -> { }); proxy = new Socks4Proxy("username"); proxy.start(vertx, v -> { server.listen(ar -> { assertTrue(ar.succeeded()); client.connect(1234, "localhost", ar2 -> { if (ar2.failed()) { log.warn("failed", ar2.cause()); } assertTrue(ar2.succeeded()); // make sure we have gone through the proxy assertEquals("localhost:1234", proxy.getLastUri()); testComplete(); }); }); }); await(); } /** * test socks4a proxy for accessing arbitrary server port using an already resolved address. */ @Test public void testWithSocks4LocalResolver() { NetClientOptions clientOptions = new NetClientOptions() .setProxyOptions(new ProxyOptions().setType(ProxyType.SOCKS4).setPort(11080)); NetClient client = vertx.createNetClient(clientOptions); server.connectHandler(sock -> { }); proxy = new Socks4Proxy(null); proxy.start(vertx, v -> { server.listen(ar -> { assertTrue(ar.succeeded()); client.connect(1234, "127.0.0.1", ar2 -> { if (ar2.failed()) { log.warn("failed", ar2.cause()); } assertTrue(ar2.succeeded()); // make sure we have gone through the proxy assertEquals("127.0.0.1:1234", proxy.getLastUri()); testComplete(); }); }); }); await(); } @Test public void testTLSHostnameCertCheckCorrect() { server.close(); server = vertx.createNetServer(new NetServerOptions().setSsl(true).setPort(4043) .setKeyCertOptions(Cert.SERVER_JKS_ROOT_CA.get())); server.connectHandler(netSocket -> netSocket.close()).listen(ar -> { NetClientOptions options = new NetClientOptions() .setHostnameVerificationAlgorithm("HTTPS") .setTrustOptions(Trust.SERVER_JKS_ROOT_CA.get()); NetClient client = vertx.createNetClient(options); client.connect(4043, "localhost", arSocket -> { if (arSocket.succeeded()) { NetSocket ns = arSocket.result(); ns.exceptionHandler(th -> { fail(th); }); ns.upgradeToSsl(v -> { testComplete(); }); } else { fail(ar.cause()); } }); }); await(); } @Test public void testTLSHostnameCertCheckIncorrect() { server.close(); server = vertx.createNetServer(new NetServerOptions().setSsl(true).setPort(4043) .setKeyCertOptions(Cert.SERVER_JKS_ROOT_CA.get())); server.connectHandler(netSocket -> netSocket.close()).listen(ar -> { NetClientOptions options = new NetClientOptions() .setHostnameVerificationAlgorithm("HTTPS") .setTrustOptions(Trust.SERVER_JKS_ROOT_CA.get()); NetClient client = vertx.createNetClient(options); client.connect(4043, "127.0.0.1", arSocket -> { if (arSocket.succeeded()) { NetSocket ns = arSocket.result(); ns.exceptionHandler(th -> { testComplete(); }); ns.upgradeToSsl(v -> { fail("this test should fail"); }); } else { fail(ar.cause()); } }); }); await(); } @Test public void testClientLocalAddress() throws Exception { String expectedAddress = InetAddress.getLocalHost().getHostAddress(); NetClientOptions clientOptions = new NetClientOptions().setLocalAddress(expectedAddress); client.close(); client = vertx.createNetClient(clientOptions); server.connectHandler(sock -> { assertEquals(expectedAddress, sock.remoteAddress().host()); sock.close(); }); server.listen(1234, "localhost", onSuccess(v -> { client.connect(1234, "localhost", onSuccess(socket -> { socket.closeHandler(v2 -> { testComplete(); }); })); })); await(); } @Test public void testSelfSignedCertificate() throws Exception { CountDownLatch latch = new CountDownLatch(2); SelfSignedCertificate certificate = SelfSignedCertificate.create(); NetServerOptions serverOptions = new NetServerOptions() .setSsl(true) .setKeyCertOptions(certificate.keyCertOptions()) .setTrustOptions(certificate.trustOptions()); NetClientOptions clientOptions = new NetClientOptions() .setSsl(true) .setKeyCertOptions(certificate.keyCertOptions()) .setTrustOptions(certificate.trustOptions()); NetClientOptions clientTrustAllOptions = new NetClientOptions() .setSsl(true) .setTrustAll(true); server = vertx.createNetServer(serverOptions) .connectHandler(socket -> { socket.write("123").end(); }) .listen(1234, "localhost", onSuccess(s -> { client = vertx.createNetClient(clientOptions); client.connect(1234, "localhost", onSuccess(socket -> { socket.handler(buffer -> { assertEquals("123", buffer.toString()); latch.countDown(); }); })); client = vertx.createNetClient(clientTrustAllOptions); client.connect(1234, "localhost", onSuccess(socket -> { socket.handler(buffer -> { assertEquals("123", buffer.toString()); latch.countDown(); }); })); })); awaitLatch(latch); } @Test public void testWorkerClient() throws Exception { String expected = TestUtils.randomAlphaString(2000); server.connectHandler(so -> { so.write(expected).close(); }); startServer(); vertx.deployVerticle(new AbstractVerticle() { @Override public void start() throws Exception { NetClient client = vertx.createNetClient(); client.connect(1234, "localhost", onSuccess(so ->{ Buffer received = Buffer.buffer(); so.handler(received::appendBuffer); so.closeHandler(v -> { assertEquals(expected, received.toString()); testComplete(); }); try { Thread.sleep(500); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } })); } }, new DeploymentOptions().setWorker(true)); await(); } @Test public void testWorkerServer() throws Exception { String expected = TestUtils.randomAlphaString(2000); vertx.deployVerticle(new AbstractVerticle() { @Override public void start(Future<Void> startFuture) throws Exception { NetServer server = vertx.createNetServer(); server.connectHandler(so -> { Buffer received = Buffer.buffer(); so.handler(received::appendBuffer); so.closeHandler(v -> { assertEquals(expected, received.toString()); testComplete(); }); try { Thread.sleep(500); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }); server.listen(1234, ar -> startFuture.handle(ar.mapEmpty())); } }, new DeploymentOptions().setWorker(true), onSuccess(v -> { client.connect(1234, "localhost", onSuccess(so -> { so.write(expected).close(); })); })); await(); } protected void startServer() throws Exception { startServer(vertx.getOrCreateContext()); } protected void startServer(NetServer server) throws Exception { startServer(vertx.getOrCreateContext(), server); } protected void startServer(Context context) throws Exception { startServer(context, server); } protected void startServer(Context context, NetServer server) throws Exception { CountDownLatch latch = new CountDownLatch(1); context.runOnContext(v -> { server.listen(onSuccess(s -> latch.countDown())); }); awaitLatch(latch); } }