final TcpChannel handshakeChannel = channels.get(0); try { executeHandshake(node, handshakeChannel, connectionProfile, new ActionListener<Version>() { @Override public void onResponse(Version version) {
private InetSocketAddress bindToPort(final String name, final InetAddress hostAddress, String port) { PortsRange portsRange = new PortsRange(port); final AtomicReference<Exception> lastException = new AtomicReference<>(); final AtomicReference<InetSocketAddress> boundSocket = new AtomicReference<>(); boolean success = portsRange.iterate(portNumber -> { try { TcpServerChannel channel = bind(name, new InetSocketAddress(hostAddress, portNumber)); synchronized (serverChannels) { List<TcpServerChannel> list = serverChannels.get(name); if (list == null) { list = new ArrayList<>(); serverChannels.put(name, list); } list.add(channel); boundSocket.set(channel.getLocalAddress()); } } catch (Exception e) { lastException.set(e); return false; } return true; }); if (!success) { throw new BindTransportException("Failed to bind to [" + port + "]", lastException.get()); } if (logger.isDebugEnabled()) { logger.debug("Bound profile [{}] to address {{}}", name, NetworkAddress.format(boundSocket.get())); } return boundSocket.get(); }
protected void bindServer(ProfileSettings profileSettings) { // Bind and start to accept incoming connections. InetAddress[] hostAddresses; List<String> profileBindHosts = profileSettings.bindHosts; try { hostAddresses = networkService.resolveBindHostAddresses(profileBindHosts.toArray(Strings.EMPTY_ARRAY)); } catch (IOException e) { throw new BindTransportException("Failed to resolve host " + profileBindHosts, e); } if (logger.isDebugEnabled()) { String[] addresses = new String[hostAddresses.length]; for (int i = 0; i < hostAddresses.length; i++) { addresses[i] = NetworkAddress.format(hostAddresses[i]); } logger.debug("binding server bootstrap to: {}", (Object) addresses); } assert hostAddresses.length > 0; List<InetSocketAddress> boundAddresses = new ArrayList<>(); for (InetAddress hostAddress : hostAddresses) { boundAddresses.add(bindToPort(profileSettings.profileName, hostAddress, profileSettings.portOrRange)); } final BoundTransportAddress boundTransportAddress = createBoundTransportAddress(profileSettings, boundAddresses); if (profileSettings.isDefaultProfile) { this.boundAddress = boundTransportAddress; } else { profileBoundAddresses.put(profileSettings.profileName, boundTransportAddress); } }
stream.setVersion(nodeVersion); stream.setFeatures(features); BytesReference message = buildMessage(requestId, status, nodeVersion, response, stream); internalSendMessage(channel, message, releaseListener); addedReleaseListener = true; } finally {
final boolean compressMessage = compressRequest && canCompress(request); BytesReference message = buildMessage(requestId, status, node.getVersion(), request, stream); final TransportRequestOptions finalOptions = options; internalSendMessage(channel, message, releaseListener); addedReleaseListener = true; } finally {
if (options.compress() && canCompress(request)) { status = TransportStatus.setCompress(status); stream = CompressorFactory.COMPRESSOR.streamOutput(stream); Version version = Version.min(getCurrentVersion(), channelVersion); BytesReference message = buildMessage(requestId, status, node.getVersion(), request, stream, bStream); final TransportRequestOptions finalOptions = options; final StreamOutput finalStream = stream; addedReleaseListener = internalSendMessage(targetChannel, message, onRequestSent); } finally { IOUtils.close(stream);
public final class NodeChannels implements Connection { private final Map<TransportRequestOptions.Type, ConnectionProfile.ConnectionTypeHandle> typeMapping; private final List<TcpChannel> channels; private final DiscoveryNode node; private final AtomicBoolean closed = new AtomicBoolean(false); private final Version version; NodeChannels(DiscoveryNode node, List<TcpChannel> channels, ConnectionProfile connectionProfile, Version handshakeVersion) { this.node = node; this.channels = Collections.unmodifiableList(channels); assert channels.size() == connectionProfile.getNumConnections() : "expected channels size to be == " + connectionProfile.getNumConnections() + " but was: [" + channels.size() + "]"; typeMapping = new EnumMap<>(TransportRequestOptions.Type.class); for (ConnectionProfile.ConnectionTypeHandle handle : connectionProfile.getHandles()) { for (TransportRequestOptions.Type type : handle.getTypes()) typeMapping.put(type, handle); } version = handshakeVersion; } @Override public Version getVersion() { return version; } public List<TcpChannel> getChannels() { return channels; } public TcpChannel channel(TransportRequestOptions.Type type) {
@Override protected void doStart() { boolean success = false; try { if (NetworkService.NETWORK_SERVER.get(settings)) { // loop through all profiles and start them up, special handling for default one for (ProfileSettings profileSettings : profileSettings) { bindServer(profileSettings); } } super.doStart(); success = true; } finally { if (success == false) { doStop(); } } }
connectionProfile = maybeOverrideConnectionProfile(connectionProfile); ensureOpen(); try { int numConnections = connectionProfile.getNumConnections(); PlainActionFuture<Void> connectFuture = PlainActionFuture.newFuture(); connectionFutures.add(connectFuture); TcpChannel channel = initiateChannel(node, connectFuture); logger.trace(() -> new ParameterizedMessage("Tcp transport client channel opened: {}", channel)); channels.add(channel); handshakeChannel.addCloseListener(ActionListener.wrap(() -> cancelHandshakeForChannel(handshakeChannel))); Version version; try { version = executeHandshake(node, handshakeChannel, connectionProfile.getHandshakeTimeout()); } catch (Exception ex) { TcpChannel.closeChannels(channels, false);
connectionProfile = resolveConnectionProfile(connectionProfile, defaultConnectionProfile); ensureOpen(); try { AtomicBoolean runOnce = new AtomicBoolean(false); onChannelClosed(c); } finally { disconnectFromNodeChannel(c, "channel closed"); nodeChannels = connectToChannels(node, connectionProfile, onClose); final Channel channel = nodeChannels.getChannels().get(0); // one channel is guaranteed by the connection profile final TimeValue connectTimeout = connectionProfile.getConnectTimeout() == null ? final TimeValue handshakeTimeout = connectionProfile.getHandshakeTimeout() == null ? connectTimeout : connectionProfile.getHandshakeTimeout(); final Version version = executeHandshake(node, channel, handshakeTimeout); if (version != null) {
@Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { try { boolean continueProcessing = TcpTransport.validateMessageHeader(Netty4Utils.toBytesReference(in)); final ByteBuf message = in.skipBytes(TcpHeader.MARKER_BYTES_SIZE + TcpHeader.MESSAGE_LENGTH_SIZE); if (!continueProcessing) return; out.add(message); } catch (IllegalArgumentException ex) { throw new TooLongFrameException(ex); } catch (IllegalStateException ex) { /* decode will be called until the ByteBuf is fully consumed; when it is fully * consumed, transport#validateMessageHeader will throw an IllegalStateException which * is okay, it means we have finished consuming the ByteBuf and we can get out */ } }
stream.setFeatures(features); RemoteTransportException tx = new RemoteTransportException( nodeName(), new TransportAddress(channel.getLocalAddress()), action, error); threadPool.getThreadContext().writeTo(stream); stream.writeException(tx); status = TransportStatus.setError(status); final BytesReference bytes = stream.bytes(); final BytesReference header = buildHeader(requestId, status, nodeVersion, bytes.length()); CompositeBytesReference message = new CompositeBytesReference(header, bytes); SendListener onResponseSent = new SendListener(channel, null, () -> messageListener.onResponseSent(requestId, action, error), message.length()); internalSendMessage(channel, message, onResponseSent);
/** * Sends back an error response to the caller via the given channel * @param nodeVersion the caller node version * @param channel the channel to send the response to * @param error the error to return * @param requestId the request ID this response replies to * @param action the action this response replies to */ public void sendErrorResponse(Version nodeVersion, Channel channel, final Exception error, final long requestId, final String action) throws IOException { try (BytesStreamOutput stream = new BytesStreamOutput()) { stream.setVersion(nodeVersion); RemoteTransportException tx = new RemoteTransportException( nodeName(), new InetSocketTransportAddress(getLocalAddress(channel)), action, error); threadPool.getThreadContext().writeTo(stream); stream.writeException(tx); byte status = 0; status = TransportStatus.setResponse(status); status = TransportStatus.setError(status); final BytesReference bytes = stream.bytes(); final BytesReference header = buildHeader(requestId, status, nodeVersion, bytes.length()); Runnable onRequestSent = () -> transportServiceAdapter.onResponseSent(requestId, action, error); sendMessage(channel, new CompositeBytesReference(header, bytes), onRequestSent); } }
TcpTransport.NodeChannels connection = originalTransport.openConnection( new DiscoveryNode("TS_TPC", "TS_TPC", service.boundAddress().publishAddress(), emptyMap(), emptySet(), version0), null )) { Version version = originalTransport.executeHandshake(connection.getNode(), connection.channel(TransportRequestOptions.Type.PING), TimeValue.timeValueSeconds(10)); assertEquals(version, Version.CURRENT);
status = TransportStatus.setError(status); final BytesReference bytes = stream.bytes(); final BytesReference header = buildHeader(requestId, status, nodeVersion, bytes.length()); CompositeBytesReference message = new CompositeBytesReference(header, bytes); ReleaseListener releaseListener = new ReleaseListener(null, () -> messageListener.onResponseSent(requestId, action, error)); internalSendMessage(channel, message, releaseListener);
BytesReference reference = buildMessage(requestId, status, nodeVersion, response, stream, bStream); addedReleaseListener = internalSendMessage(channel, reference, onRequestSent); } finally { if (!addedReleaseListener) {
private static boolean appearsToBeHTTP(BytesReference headerBuffer) { return bufferStartsWith(headerBuffer, "GET") || bufferStartsWith(headerBuffer, "POST") || bufferStartsWith(headerBuffer, "PUT") || bufferStartsWith(headerBuffer, "HEAD") || bufferStartsWith(headerBuffer, "DELETE") || // Actually 'OPTIONS'. But we are only guaranteed to have read six bytes at this point. bufferStartsWith(headerBuffer, "OPTION") || bufferStartsWith(headerBuffer, "PATCH") || bufferStartsWith(headerBuffer, "TRACE"); }
/** * Serializes the given message into a bytes representation */ private BytesReference buildMessage(long requestId, byte status, Version nodeVersion, TransportMessage message, CompressibleBytesOutputStream stream) throws IOException { final BytesReference zeroCopyBuffer; if (message instanceof BytesTransportRequest) { // what a shitty optimization - we should use a direct send method instead BytesTransportRequest bRequest = (BytesTransportRequest) message; assert nodeVersion.equals(bRequest.version()); bRequest.writeThin(stream); zeroCopyBuffer = bRequest.bytes; } else { message.writeTo(stream); zeroCopyBuffer = BytesArray.EMPTY; } // we have to call materializeBytes() here before accessing the bytes. A CompressibleBytesOutputStream // might be implementing compression. And materializeBytes() ensures that some marker bytes (EOS marker) // are written. Otherwise we barf on the decompressing end when we read past EOF on purpose in the // #validateRequest method. this might be a problem in deflate after all but it's important to write // the marker bytes. final BytesReference messageBody = stream.materializeBytes(); final BytesReference header = buildHeader(requestId, status, stream.getVersion(), messageBody.length() + zeroCopyBuffer.length()); return new CompositeBytesReference(header, messageBody, zeroCopyBuffer); }
protected InetSocketAddress bindToPort(final String name, final InetAddress hostAddress, String port) { PortsRange portsRange = new PortsRange(port); final AtomicReference<Exception> lastException = new AtomicReference<>(); final AtomicReference<InetSocketAddress> boundSocket = new AtomicReference<>(); boolean success = portsRange.iterate(portNumber -> { try { Channel channel = bind(name, new InetSocketAddress(hostAddress, portNumber)); synchronized (serverChannels) { List<Channel> list = serverChannels.get(name); if (list == null) { list = new ArrayList<>(); serverChannels.put(name, list); } list.add(channel); boundSocket.set(getLocalAddress(channel)); } } catch (Exception e) { lastException.set(e); return false; } return true; }); if (!success) { throw new BindTransportException("Failed to bind to [" + port + "]", lastException.get()); } if (logger.isDebugEnabled()) { logger.debug("Bound profile [{}] to address {{}}", name, NetworkAddress.format(boundSocket.get())); } return boundSocket.get(); }
final boolean compressMessage = options.compress() && canCompress(request);