@Override public Releasable openConnection(DiscoveryNode node, ConnectionProfile profile, ActionListener<Transport.Connection> listener) { Objects.requireNonNull(profile, "connection profile cannot be null"); if (node == null) { throw new ConnectTransportException(null, "can't open connection to a null node"); } ConnectionProfile finalProfile = maybeOverrideConnectionProfile(profile); closeLock.readLock().lock(); // ensure we don't open connections while we are closing try { ensureOpen(); List<TcpChannel> pendingChannels = initiateConnection(node, finalProfile, listener); return () -> CloseableChannel.closeChannels(pendingChannels, false); } finally { closeLock.readLock().unlock(); } }
ConnectTransportException ex = expectThrows(ConnectTransportException.class, () -> serviceA.connectToNode(dummy, builder.build())); assertEquals(ex.getMessage(), "[][" + dummy.getAddress() + "] general node connection failure"); assertThat(ex.getCause().getMessage(), startsWith("handshake failed")); t.join();
@Override public void handleException(TransportException exp) { Throwable cause = ExceptionsHelper.unwrapCause(exp); assertThat(cause, instanceOf(ConnectTransportException.class)); assertThat(((ConnectTransportException) cause).node(), equalTo(nodeA)); } });
public void testTcpHandshakeTimeout() throws IOException { try (ServerSocket socket = new MockServerSocket()) { socket.bind(new InetSocketAddress(InetAddress.getLocalHost(), 0), 1); socket.setReuseAddress(true); DiscoveryNode dummy = new DiscoveryNode("TEST", new TransportAddress(socket.getInetAddress(), socket.getLocalPort()), emptyMap(), emptySet(), version0); ConnectionProfile.Builder builder = new ConnectionProfile.Builder(); builder.addConnections(1, TransportRequestOptions.Type.BULK, TransportRequestOptions.Type.PING, TransportRequestOptions.Type.RECOVERY, TransportRequestOptions.Type.REG, TransportRequestOptions.Type.STATE); builder.setHandshakeTimeout(TimeValue.timeValueMillis(1)); ConnectTransportException ex = expectThrows(ConnectTransportException.class, () -> serviceA.connectToNode(dummy, builder.build())); assertEquals("[][" + dummy.getAddress() + "] handshake_timeout[1ms]", ex.getMessage()); } }
new DiscoveryNode("TS_TPC", "TS_TPC", transport.boundAddress().publishAddress(), emptyMap(), emptySet(), version0); ConnectTransportException exception = expectThrows(ConnectTransportException.class, () -> serviceA.connectToNode(node)); assertTrue(exception.getCause() instanceof IllegalStateException); assertEquals("handshake failed", exception.getCause().getMessage());
Throwable cause = ExceptionsHelper.unwrapCause(e); assertThat(cause, instanceOf(ConnectTransportException.class)); assertThat(((ConnectTransportException) cause).node(), equalTo(nodeA));
assertTrue("test didn't timeout quick enough, time taken: [" + timeTaken + "]", timeTaken < TimeValue.timeValueSeconds(5).millis()); assertEquals(ex.getMessage(), "[][" + second.getAddress() + "] connect_timeout[1ms]");
@Override public void onFailure(Exception ex) { if (countDown.fastForward()) { CloseableChannel.closeChannels(channels, false); listener.onFailure(new ConnectTransportException(node, "connect_exception", ex)); } }
@Override public void onFailure(Exception e) { CloseableChannel.closeChannels(channels, false); if (e instanceof ConnectTransportException) { listener.onFailure(e); } else { listener.onFailure(new ConnectTransportException(node, "general node connection failure", e)); } } });
public void onTimeout() { if (countDown.fastForward()) { CloseableChannel.closeChannels(channels, false); listener.onFailure(new ConnectTransportException(node, "connect_timeout[" + connectionProfile.getConnectTimeout() + "]")); } } }
public CheckedBiConsumer<Transport.Connection, ConnectionProfile, IOException> connectionValidator(DiscoveryNode node) { return (newConnection, actualProfile) -> { // We don't validate cluster names to allow for CCS connections. final DiscoveryNode remote = handshake(newConnection, actualProfile.getHandshakeTimeout().millis(), cn -> true).discoveryNode; if (validateConnections && node.equals(remote) == false) { throw new ConnectTransportException(node, "handshake failed. unexpected remote node " + remote); } }; }
ConnectionProfile resolvedProfile = ConnectionProfile.resolveConnectionProfile(connectionProfile, defaultProfile); if (node == null) { throw new ConnectTransportException(null, "can't connect to a null node"); throw e; } catch (Exception e) { throw new ConnectTransportException(node, "general node connection failure", e); } finally { if (success == false) { // close the connection if there is a failure
void sendHandshake(long requestId, DiscoveryNode node, TcpChannel channel, TimeValue timeout, ActionListener<Version> listener) { numHandshakes.inc(); final HandshakeResponseHandler handler = new HandshakeResponseHandler(requestId, version, listener); pendingHandshakes.put(requestId, handler); channel.addCloseListener(ActionListener.wrap( () -> handler.handleLocalException(new TransportException("handshake failed because connection reset")))); boolean success = false; try { // for the request we use the minCompatVersion since we don't know what's the version of the node we talk to // we also have no payload on the request but the response will contain the actual version of the node we talk // to as the payload. final Version minCompatVersion = version.minimumCompatibilityVersion(); handshakeRequestSender.sendRequest(node, channel, requestId, minCompatVersion); threadPool.schedule(timeout, ThreadPool.Names.GENERIC, () -> handler.handleLocalException(new ConnectTransportException(node, "handshake_timeout[" + timeout + "]"))); success = true; } catch (Exception e) { handler.handleLocalException(new ConnectTransportException(node, "failure to send " + HANDSHAKE_ACTION_NAME, e)); } finally { if (success == false) { TransportResponseHandler<?> removed = pendingHandshakes.remove(requestId); assert removed == null : "Handshake should not be pending if exception was thrown"; } } }
private List<TcpChannel> initiateConnection(DiscoveryNode node, ConnectionProfile connectionProfile, ActionListener<Transport.Connection> listener) { int numConnections = connectionProfile.getNumConnections(); assert numConnections > 0 : "A connection profile must be configured with at least one connection"; final List<TcpChannel> channels = new ArrayList<>(numConnections); for (int i = 0; i < numConnections; ++i) { try { TcpChannel channel = initiateChannel(node); logger.trace(() -> new ParameterizedMessage("Tcp transport client channel opened: {}", channel)); channels.add(channel); } catch (ConnectTransportException e) { CloseableChannel.closeChannels(channels, false); listener.onFailure(e); return channels; } catch (Exception e) { CloseableChannel.closeChannels(channels, false); listener.onFailure(new ConnectTransportException(node, "general node connection failure", e)); return channels; } } ChannelsConnectedListener channelsConnectedListener = new ChannelsConnectedListener(node, connectionProfile, channels, listener); for (TcpChannel channel : channels) { channel.addConnectListener(channelsConnectedListener); } TimeValue connectTimeout = connectionProfile.getConnectTimeout(); threadPool.schedule(connectTimeout, ThreadPool.Names.GENERIC, channelsConnectedListener::onTimeout); return channels; }
@Override public Connection openConnection(DiscoveryNode node, ConnectionProfile profile) throws IOException { throw new ConnectTransportException(node, "DISCONNECT: simulated"); }
@Override public Connection openConnection(DiscoveryNode node, ConnectionProfile profile) throws IOException { throw new ConnectTransportException(node, "UNRESPONSIVE: simulated"); }
private Transport.Connection internalOpenConnection(DiscoveryNode node, ConnectionProfile connectionProfile) { PlainActionFuture<Transport.Connection> future = PlainActionFuture.newFuture(); Releasable pendingConnection = transport.openConnection(node, connectionProfile, future); Transport.Connection connection; try { connection = future.actionGet(); } catch (IllegalStateException e) { // If the future was interrupted we must cancel the pending connection to avoid channels leaking if (e.getCause() instanceof InterruptedException) { pendingConnection.close(); } throw e; } try { connectionListener.onConnectionOpened(connection); } finally { connection.addCloseListener(ActionListener.wrap(() -> connectionListener.onConnectionClosed(connection))); } if (connection.isClosed()) { throw new ConnectTransportException(node, "a channel closed while connecting"); } return connection; }
@Override public void connectToNode(DiscoveryNode node, ConnectionProfile connectionProfile, CheckedBiConsumer<Connection, ConnectionProfile, IOException> connectionValidator) throws ConnectTransportException { if (original.nodeConnected(node) == false) { // connecting to an already connected node is a no-op throw new ConnectTransportException(node, "DISCONNECT: simulated"); } }
@Override public void connectToNode(DiscoveryNode node, ConnectionProfile connectionProfile, CheckedBiConsumer<Connection, ConnectionProfile, IOException> connectionValidator) throws ConnectTransportException { if (original.nodeConnected(node) == false) { // connecting to an already connected node is a no-op throw new ConnectTransportException(node, "UNRESPONSIVE: simulated"); } }
@Override public Connection openConnection(DiscoveryNode node, ConnectionProfile profile) throws IOException { final LocalTransport targetTransport = transports.get(node.getAddress()); if (targetTransport == null) { throw new ConnectTransportException(node, "Failed to connect"); } return getConnectionForTransport(targetTransport, node, false); }