Ejemplo n.º 1
0
  @Override
  protected void channelRead0(final ChannelHandlerContext ctx, final Message responseMessage)
      throws Exception {
    MessageID recvMessageID = new MessageID(responseMessage);
    // Error handling
    if (responseMessage.type() == Message.Type.UNKNOWN_ID) {
      String msg =
          "Message was not delivered successfully, unknown ID (peer may be offline or unknown RPC handler): "
              + this.message;
      exceptionCaught(ctx, new PeerException(PeerException.AbortCause.PEER_ABORT, msg));
      responseMessage.release();
      return;
    }
    if (responseMessage.type() == Message.Type.EXCEPTION) {
      String msg =
          "Message caused an exception on the other side, handle as peer_abort: " + this.message;
      exceptionCaught(ctx, new PeerException(PeerException.AbortCause.PEER_ABORT, msg));
      responseMessage.release();
      return;
    }
    if (responseMessage.isRequest()) {
      ctx.fireChannelRead(responseMessage);
      return;
    }
    if (!sendMessageID.equals(recvMessageID)) {
      String msg =
          "Response message ["
              + responseMessage
              + "] sent to the node is not the same as we expect. We sent ["
              + this.message
              + "]";
      exceptionCaught(ctx, new PeerException(PeerException.AbortCause.PEER_ABORT, msg));
      responseMessage.release();
      return;
    }
    // We need to exclude RCON Messages from the sanity check because we
    // use this RequestHandler for sending a Type.REQUEST_1,
    // RPC.Commands.RCON message on top of it. Therefore the response
    // type will never be the same Type as the one the user initially
    // used (e.g. DIRECT_DATA).
    /*if (responseMessage.command() != RPC.Commands.RCON.getNr()
    	&& message.recipient().isRelayed() != responseMessage.sender().isRelayed()) {
    String msg = "Response message [" + responseMessage + "] sent has a different relay flag than we sent with request message ["
    		+ this.message + "]. Recipient (" + message.recipient().isRelayed() + ") / Sender ("
    		+ responseMessage.sender().isRelayed() + ")";
    LOG.warn(msg);
         }*/

    // NAT reflection, change it back, as this will be stored in our peer map that may be queried
    // from other peers
    if (message.recipientReflected() != null) {
      responseMessage.sender(message.recipient().withIpv4Socket(message.recipient().ipv4Socket()));
    }

    // Stop time measurement of RTT
    futureResponse.stopRTTMeasurement();

    // We got a good answer, let's mark the sender as alive
    // if its an announce, the peer status will be handled in the RPC
    if (responseMessage.isOk() || responseMessage.isNotOk()) {
      LOG.debug("Try adding peer {} to map, {}", responseMessage.sender(), responseMessage);
      peerBean.notifyPeerFound(
          responseMessage.sender(), null, null, futureResponse.getRoundTripTime());
    }

    // call this for streaming support
    if (!responseMessage.isDone()) {
      LOG.debug("Good message is streaming. {}", responseMessage);
      return;
    }

    // support slow, unreachable devices which cannot respond instantly
    if (this.message.recipient().relaySize() > 0
        && this.message.recipient().slow()
        && responseMessage.type() == Message.Type.PARTIALLY_OK) {
      LOG.debug(
          "Received partially ok by the relay peer. Wait for answer of the unreachable peer.");
      // wait for the (real) answer of the unreachable peer.
      connectionBean
          .dispatcher()
          .addPendingRequest(
              message.messageId(),
              futureResponse,
              slowResponseTimeoutSeconds,
              connectionBean.timer());
      // close the channel to the relay peer
      ctx.close();
      return;
    }

    if (!message.isKeepAlive()) {
      LOG.debug("Good message {}. Close channel {}.", responseMessage, ctx.channel());
      // set the success now, but trigger the notify when we closed the channel.
      futureResponse.responseLater(responseMessage);
      // the channel creator adds a listener that sets futureResponse.setResponseNow, when the
      // channel
      // is closed
      ctx.close();
    } else {
      LOG.debug("Good message {}. Leave channel {} open.", responseMessage, ctx.channel());
      futureResponse.response(responseMessage);
    }
  }