protected void messageReceived(
      byte[] data,
      String action,
      LocalTransport sourceTransport,
      Version version,
      @Nullable final Long sendRequestId) {
    Transports.assertTransportThread();
    try {
      transportServiceAdapter.received(data.length);
      StreamInput stream = StreamInput.wrap(data);
      stream.setVersion(version);

      long requestId = stream.readLong();
      byte status = stream.readByte();
      boolean isRequest = TransportStatus.isRequest(status);
      if (isRequest) {
        ThreadContext threadContext = threadPool.getThreadContext();
        threadContext.readHeaders(stream);
        handleRequest(stream, requestId, data.length, sourceTransport, version);
      } else {
        final TransportResponseHandler handler =
            transportServiceAdapter.onResponseReceived(requestId);
        // ignore if its null, the adapter logs it
        if (handler != null) {
          if (TransportStatus.isError(status)) {
            handleResponseError(stream, handler);
          } else {
            handleResponse(stream, sourceTransport, handler);
          }
        }
      }
    } catch (Throwable e) {
      if (sendRequestId != null) {
        TransportResponseHandler handler =
            sourceTransport.transportServiceAdapter.onResponseReceived(sendRequestId);
        if (handler != null) {
          RemoteTransportException error =
              new RemoteTransportException(nodeName(), localAddress, action, e);
          sourceTransport
              .workers()
              .execute(
                  () -> {
                    ThreadContext threadContext = sourceTransport.threadPool.getThreadContext();
                    try (ThreadContext.StoredContext ignore = threadContext.stashContext()) {
                      sourceTransport.handleException(handler, error);
                    }
                  });
        }
      } else {
        logger.warn("Failed to receive message for action [{}]", e, action);
      }
    }
  }
  protected String handleRequest(
      Channel channel, StreamInput buffer, long requestId, Version version) throws IOException {
    final String action = buffer.readString();

    final NettyTransportChannel transportChannel =
        new NettyTransportChannel(transport, action, channel, requestId, version);
    try {
      final TransportRequestHandler handler = transportServiceAdapter.handler(action);
      if (handler == null) {
        throw new ActionNotFoundTransportException(action);
      }
      final TransportRequest request = handler.newInstance();
      request.remoteAddress(
          new InetSocketTransportAddress((InetSocketAddress) channel.getRemoteAddress()));
      request.readFrom(buffer);
      if (handler.executor() == ThreadPool.Names.SAME) {
        //noinspection unchecked
        handler.messageReceived(request, transportChannel);
      } else {
        threadPool
            .executor(handler.executor())
            .execute(new RequestHandler(handler, request, transportChannel, action));
      }
    } catch (Throwable e) {
      try {
        transportChannel.sendResponse(e);
      } catch (IOException e1) {
        logger.warn("Failed to send error message back to client for action [" + action + "]", e);
        logger.warn("Actual Exception", e1);
      }
    }
    return action;
  }
 @Override
 public void disconnectFromNode(DiscoveryNode node) {
   synchronized (this) {
     LocalTransport removed = connectedNodes.remove(node);
     if (removed != null) {
       transportServiceAdapter.raiseNodeDisconnected(node);
     }
   }
 }
  @Override
  public void sendRequest(
      final DiscoveryNode node,
      final long requestId,
      final String action,
      final TransportRequest request,
      TransportRequestOptions options)
      throws IOException, TransportException {
    final Version version = Version.smallest(node.getVersion(), this.version);

    try (BytesStreamOutput stream = new BytesStreamOutput()) {
      stream.setVersion(version);

      stream.writeLong(requestId);
      byte status = 0;
      status = TransportStatus.setRequest(status);
      stream.writeByte(status); // 0 for request, 1 for response.

      threadPool.getThreadContext().writeTo(stream);
      stream.writeString(action);
      request.writeTo(stream);

      stream.close();

      final LocalTransport targetTransport = connectedNodes.get(node);
      if (targetTransport == null) {
        throw new NodeNotConnectedException(node, "Node not connected");
      }

      final byte[] data = stream.bytes().toBytes();
      transportServiceAdapter.sent(data.length);
      transportServiceAdapter.onRequestSent(node, requestId, action, request, options);
      targetTransport
          .workers()
          .execute(
              () -> {
                ThreadContext threadContext = targetTransport.threadPool.getThreadContext();
                try (ThreadContext.StoredContext context = threadContext.stashContext()) {
                  targetTransport.messageReceived(
                      data, action, LocalTransport.this, version, requestId);
                }
              });
    }
  }
 @Override
 public void connectToNode(DiscoveryNode node) throws ConnectTransportException {
   synchronized (this) {
     if (connectedNodes.containsKey(node)) {
       return;
     }
     final LocalTransport targetTransport = transports.get(node.getAddress());
     if (targetTransport == null) {
       throw new ConnectTransportException(node, "Failed to connect");
     }
     connectedNodes.put(node, targetTransport);
     transportServiceAdapter.raiseNodeConnected(node);
   }
 }
  @Override
  public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
    Object m = e.getMessage();
    if (!(m instanceof ChannelBuffer)) {
      ctx.sendUpstream(e);
      return;
    }
    ChannelBuffer buffer = (ChannelBuffer) m;
    int size = buffer.getInt(buffer.readerIndex() - 4);
    transportServiceAdapter.received(size + 6);

    // we have additional bytes to read, outside of the header
    boolean hasMessageBytesToRead = (size - (NettyHeader.HEADER_SIZE - 6)) != 0;

    int markedReaderIndex = buffer.readerIndex();
    int expectedIndexReader = markedReaderIndex + size;

    // netty always copies a buffer, either in NioWorker in its read handler, where it copies to a
    // fresh
    // buffer, or in the cumlation buffer, which is cleaned each time
    StreamInput streamIn = ChannelBufferStreamInputFactory.create(buffer, size);

    long requestId = buffer.readLong();
    byte status = buffer.readByte();
    Version version = Version.fromId(buffer.readInt());

    StreamInput wrappedStream;
    if (TransportStatus.isCompress(status) && hasMessageBytesToRead && buffer.readable()) {
      Compressor compressor = CompressorFactory.compressor(buffer);
      if (compressor == null) {
        int maxToRead = Math.min(buffer.readableBytes(), 10);
        int offset = buffer.readerIndex();
        StringBuilder sb =
            new StringBuilder("stream marked as compressed, but no compressor found, first [")
                .append(maxToRead)
                .append("] content bytes out of [")
                .append(buffer.readableBytes())
                .append("] readable bytes with message size [")
                .append(size)
                .append("] ")
                .append("] are [");
        for (int i = 0; i < maxToRead; i++) {
          sb.append(buffer.getByte(offset + i)).append(",");
        }
        sb.append("]");
        throw new ElasticsearchIllegalStateException(sb.toString());
      }
      wrappedStream = CachedStreamInput.cachedHandlesCompressed(compressor, streamIn);
    } else {
      wrappedStream = CachedStreamInput.cachedHandles(streamIn);
    }
    wrappedStream.setVersion(version);

    if (TransportStatus.isRequest(status)) {
      String action = handleRequest(ctx.getChannel(), wrappedStream, requestId, version);
      if (buffer.readerIndex() != expectedIndexReader) {
        if (buffer.readerIndex() < expectedIndexReader) {
          logger.warn(
              "Message not fully read (request) for [{}] and action [{}], resetting",
              requestId,
              action);
        } else {
          logger.warn(
              "Message read past expected size (request) for [{}] and action [{}], resetting",
              requestId,
              action);
        }
        buffer.readerIndex(expectedIndexReader);
      }
    } else {
      TransportResponseHandler handler = transportServiceAdapter.remove(requestId);
      // ignore if its null, the adapter logs it
      if (handler != null) {
        if (TransportStatus.isError(status)) {
          handlerResponseError(wrappedStream, handler);
        } else {
          handleResponse(ctx.getChannel(), wrappedStream, handler);
        }
      } else {
        // if its null, skip those bytes
        buffer.readerIndex(markedReaderIndex + size);
      }
      if (buffer.readerIndex() != expectedIndexReader) {
        if (buffer.readerIndex() < expectedIndexReader) {
          logger.warn(
              "Message not fully read (response) for [{}] handler {}, error [{}], resetting",
              requestId,
              handler,
              TransportStatus.isError(status));
        } else {
          logger.warn(
              "Message read past expected size (response) for [{}] handler {}, error [{}], resetting",
              requestId,
              handler,
              TransportStatus.isError(status));
        }
        buffer.readerIndex(expectedIndexReader);
      }
    }
    wrappedStream.close();
  }
 @Override
 public void writeComplete(ChannelHandlerContext ctx, WriteCompletionEvent e) throws Exception {
   transportServiceAdapter.sent(e.getWrittenAmount());
   super.writeComplete(ctx, e);
 }
 /**
  * simulate an error for the given requestId, unlike {@link #handleLocalError(long, Throwable)}
  * and {@link #handleRemoteError(long, Throwable)}, the provided exception will not be wrapped but
  * will be delivered to the transport layer as is
  *
  * @param requestId the id corresponding to the captured send request
  * @param e the failure
  */
 public void handleError(final long requestId, final TransportException e) {
   adapter.onResponseReceived(requestId).handleException(e);
 }
 /** simulate a response for the given requestId */
 public void handleResponse(final long requestId, final TransportResponse response) {
   adapter.onResponseReceived(requestId).handleResponse(response);
 }
Example #10
0
  private void handleRequest(
      StreamInput stream,
      long requestId,
      int messageLengthBytes,
      LocalTransport sourceTransport,
      Version version)
      throws Exception {
    stream = new NamedWriteableAwareStreamInput(stream, namedWriteableRegistry);
    final String action = stream.readString();
    transportServiceAdapter.onRequestReceived(requestId, action);
    inFlightRequestsBreaker()
        .addEstimateBytesAndMaybeBreak(messageLengthBytes, "<transport_request>");
    final LocalTransportChannel transportChannel =
        new LocalTransportChannel(
            this,
            transportServiceAdapter,
            sourceTransport,
            action,
            requestId,
            version,
            messageLengthBytes);
    try {
      final RequestHandlerRegistry reg = transportServiceAdapter.getRequestHandler(action);
      if (reg == null) {
        throw new ActionNotFoundTransportException("Action [" + action + "] not found");
      }
      final TransportRequest request = reg.newRequest();
      request.remoteAddress(sourceTransport.boundAddress.publishAddress());
      request.readFrom(stream);
      if (ThreadPool.Names.SAME.equals(reg.getExecutor())) {
        //noinspection unchecked
        reg.processMessageReceived(request, transportChannel);
      } else {
        threadPool
            .executor(reg.getExecutor())
            .execute(
                new AbstractRunnable() {
                  @Override
                  protected void doRun() throws Exception {
                    //noinspection unchecked
                    reg.processMessageReceived(request, transportChannel);
                  }

                  @Override
                  public boolean isForceExecution() {
                    return reg.isForceExecution();
                  }

                  @Override
                  public void onFailure(Throwable e) {
                    if (lifecycleState() == Lifecycle.State.STARTED) {
                      // we can only send a response transport is started....
                      try {
                        transportChannel.sendResponse(e);
                      } catch (Throwable e1) {
                        logger.warn(
                            "Failed to send error message back to client for action [{}]",
                            e1,
                            action);
                        logger.warn("Actual Exception", e);
                      }
                    }
                  }
                });
      }
    } catch (Throwable e) {
      try {
        transportChannel.sendResponse(e);
      } catch (Throwable e1) {
        logger.warn("Failed to send error message back to client for action [{}]", e, action);
        logger.warn("Actual Exception", e1);
      }
    }
  }