use of org.hyperledger.besu.ethereum.p2p.rlpx.wire.messages.DisconnectMessage in project besu by hyperledger.
the class DeFramerTest method decode_shouldHandleImmediateDisconnectMessage.
@Test
public void decode_shouldHandleImmediateDisconnectMessage() {
DisconnectMessage disconnectMessage = DisconnectMessage.create(DisconnectReason.TOO_MANY_PEERS);
ByteBuf disconnectData = Unpooled.wrappedBuffer(disconnectMessage.getData().toArray());
when(framer.deframe(eq(disconnectData))).thenReturn(new RawMessage(disconnectMessage.getCode(), disconnectMessage.getData())).thenReturn(null);
List<Object> out = new ArrayList<>();
deFramer.decode(ctx, disconnectData, out);
assertThat(connectFuture).isDone();
assertThatThrownBy(connectFuture::get).hasCauseInstanceOf(PeerDisconnectedException.class).hasMessageContaining(disconnectMessage.getReason().toString());
verify(ctx).close();
assertThat(out).isEmpty();
}
use of org.hyperledger.besu.ethereum.p2p.rlpx.wire.messages.DisconnectMessage in project besu by hyperledger.
the class DeFramer method decode.
@Override
protected void decode(final ChannelHandlerContext ctx, final ByteBuf in, final List<Object> out) {
MessageData message;
while ((message = framer.deframe(in)) != null) {
if (hellosExchanged) {
out.add(message);
} else if (message.getCode() == WireMessageCodes.HELLO) {
hellosExchanged = true;
// Decode first hello and use the payload to modify pipeline
final PeerInfo peerInfo;
try {
peerInfo = HelloMessage.readFrom(message).getPeerInfo();
} catch (final RLPException e) {
LOG.debug("Received invalid HELLO message, set log level to TRACE for message body", e);
connectFuture.completeExceptionally(e);
ctx.close();
return;
}
LOG.trace("Received HELLO message: {}", peerInfo);
if (peerInfo.getVersion() >= 5) {
LOG.trace("Enable compression for p2pVersion: {}", peerInfo.getVersion());
framer.enableCompression();
}
final CapabilityMultiplexer capabilityMultiplexer = new CapabilityMultiplexer(subProtocols, localNode.getPeerInfo().getCapabilities(), peerInfo.getCapabilities());
final Optional<Peer> peer = expectedPeer.or(() -> createPeer(peerInfo, ctx));
if (peer.isEmpty()) {
LOG.debug("Failed to create connection for peer {}", peerInfo);
connectFuture.completeExceptionally(new PeerChannelClosedException(peerInfo));
ctx.close();
return;
}
final PeerConnection connection = new NettyPeerConnection(ctx, peer.get(), peerInfo, capabilityMultiplexer, connectionEventDispatcher, outboundMessagesCounter);
// Check peer is who we expected
if (expectedPeer.isPresent() && !Objects.equals(expectedPeer.get().getId(), peerInfo.getNodeId())) {
final String unexpectedMsg = String.format("Expected id %s, but got %s", expectedPeer.get().getId(), peerInfo.getNodeId());
connectFuture.completeExceptionally(new UnexpectedPeerConnectionException(unexpectedMsg));
LOG.debug("{}. Disconnecting.", unexpectedMsg);
connection.disconnect(DisconnectMessage.DisconnectReason.UNEXPECTED_ID);
}
// Check that we have shared caps
if (capabilityMultiplexer.getAgreedCapabilities().size() == 0) {
LOG.debug("Disconnecting because no capabilities are shared: {}", peerInfo);
connectFuture.completeExceptionally(new IncompatiblePeerException("No shared capabilities"));
connection.disconnect(DisconnectMessage.DisconnectReason.USELESS_PEER);
}
// Setup next stage
final AtomicBoolean waitingForPong = new AtomicBoolean(false);
ctx.channel().pipeline().addLast(new IdleStateHandler(15, 0, 0), new WireKeepAlive(connection, waitingForPong), new ApiHandler(capabilityMultiplexer, connection, connectionEventDispatcher, waitingForPong), new MessageFramer(capabilityMultiplexer, framer));
connectFuture.complete(connection);
} else if (message.getCode() == WireMessageCodes.DISCONNECT) {
final DisconnectMessage disconnectMessage = DisconnectMessage.readFrom(message);
LOG.debug("Peer {} disconnected before sending HELLO. Reason: {}", expectedPeer.map(Peer::getEnodeURLString).orElse("unknown"), disconnectMessage.getReason());
ctx.close();
connectFuture.completeExceptionally(new PeerDisconnectedException(disconnectMessage.getReason()));
} else {
// Unexpected message - disconnect
LOG.debug("Message received before HELLO's exchanged, disconnecting. Peer: {}, Code: {}, Data: {}", expectedPeer.map(Peer::getEnodeURLString).orElse("unknown"), message.getCode(), message.getData().toString());
ctx.writeAndFlush(new OutboundMessage(null, DisconnectMessage.create(DisconnectMessage.DisconnectReason.BREACH_OF_PROTOCOL))).addListener((f) -> ctx.close());
connectFuture.completeExceptionally(new BreachOfProtocolException("Message received before HELLO's exchanged"));
}
}
}
use of org.hyperledger.besu.ethereum.p2p.rlpx.wire.messages.DisconnectMessage in project besu by hyperledger.
the class ApiHandler method channelRead0.
@Override
protected void channelRead0(final ChannelHandlerContext ctx, final MessageData originalMessage) {
final CapabilityMultiplexer.ProtocolMessage demultiplexed = multiplexer.demultiplex(originalMessage);
final MessageData message = demultiplexed.getMessage();
// Handle Wire messages
if (demultiplexed.getCapability() == null) {
switch(message.getCode()) {
case WireMessageCodes.PING:
LOG.debug("Received Wire PING");
try {
connection.send(null, PongMessage.get());
} catch (final PeerConnection.PeerNotConnected peerNotConnected) {
// Nothing to do
}
break;
case WireMessageCodes.PONG:
LOG.debug("Received Wire PONG");
waitingForPong.set(false);
break;
case WireMessageCodes.DISCONNECT:
final DisconnectMessage disconnect = DisconnectMessage.readFrom(message);
DisconnectMessage.DisconnectReason reason = DisconnectMessage.DisconnectReason.UNKNOWN;
try {
reason = disconnect.getReason();
LOG.trace("Received Wire DISCONNECT ({}) from peer: {}", reason.name(), connection.getPeerInfo());
} catch (final RLPException e) {
LOG.trace("Received Wire DISCONNECT with invalid RLP. Peer: {}", connection.getPeerInfo());
} catch (final Exception e) {
LOG.error("Received Wire DISCONNECT, but unable to parse reason. Peer: {}", connection.getPeerInfo(), e);
}
connection.terminateConnection(reason, true);
}
return;
}
connectionEventDispatcher.dispatchMessage(demultiplexed.getCapability(), connection, message);
}
Aggregations