package org.ripple.power.txns.btc; import java.io.EOFException; public class MessageHandler implements Runnable { /** Message handler shutdown requested */ private boolean messageShutdown = false; /** * Creates a message handler */ public MessageHandler() { } /** * Processes messages and returns responses */ @Override public void run() { BTCLoader.info("Message handler started"); // // Process messages until we are shutdown // try { while (true) { Message msg = BTCLoader.messageQueue.take(); if (messageShutdown) break; processMessage(msg); } } catch (InterruptedException exc) { BTCLoader.warn("Message handler interrupted", exc); } catch (Throwable exc) { BTCLoader.error("Runtime exception while processing messages", exc); } // // Stopping // BTCLoader.info("Message handler stopped"); } /** * Shutdown the message handler */ public void shutdown() { try { messageShutdown = true; BTCLoader.messageQueue.put(new ShutdownMessage()); } catch (InterruptedException exc) { BTCLoader.warn("Message handler shutdown interrupted", exc); } } /** * Process a message and return a response * * @param msg Message */ private void processMessage(Message msg) throws InterruptedException { Peer peer = msg.getPeer(); if (peer == null) { BTCLoader.dumpData("Message With No Peer", msg.getBuffer().array()); return; } PeerAddress address = peer.getAddress(); int reasonCode = 0; try { MessageProcessor.processMessage(msg, BTCLoader.networkMessageListener); msg.setBuffer(null); } catch (EOFException exc) { MessageHeader.MessageCommand cmdOp = msg.getCommand(); String cmdName = (cmdOp!=null ? cmdOp.toString().toLowerCase() : "N/A"); BTCLoader.error(String.format("End-of-data while processing '%s' message from %s", cmdName, address), exc); reasonCode = RejectMessage.REJECT_MALFORMED; if (cmdOp == MessageHeader.MessageCommand.TX) BTCLoader.txRejected.incrementAndGet(); else if (cmdOp == MessageHeader.MessageCommand.VERSION) peer.setDisconnect(true); if (peer.getVersion() >= 70002) { Message rejectMsg = RejectMessage.buildRejectMessage(peer, cmdName, reasonCode, exc.getMessage()); msg.setBuffer(rejectMsg.getBuffer()); msg.setCommand(rejectMsg.getCommand()); } else { msg.setBuffer(null); } } catch (VerificationException exc) { MessageHeader.MessageCommand cmdOp = msg.getCommand(); String cmdName = (cmdOp!=null ? cmdOp.toString().toLowerCase() : "N/A"); BTCLoader.error(String.format("Message verification failed for '%s' message from %s\n %s\n %s", cmdName, address, exc.getMessage(), exc.getHash())); reasonCode = exc.getReason(); if (cmdOp == MessageHeader.MessageCommand.TX) BTCLoader.txRejected.incrementAndGet(); else if (cmdOp == MessageHeader.MessageCommand.VERSION) peer.setDisconnect(true); if (peer.getVersion() >= 70002) { Message rejectMsg = RejectMessage.buildRejectMessage(peer, cmdName, reasonCode, exc.getMessage(), exc.getHash()); msg.setBuffer(rejectMsg.getBuffer()); msg.setCommand(rejectMsg.getCommand()); } else { msg.setBuffer(null); } } // // Add the message to the completed message list and wakeup the network listener. We will // bump the banscore for the peer if the message was rejected because it was malformed // or invalid. We will ban the peer if it is using an obsolete protocol. // BTCLoader.completedMessages.add(msg); int banScore; switch (reasonCode) { case RejectMessage.REJECT_MALFORMED: case RejectMessage.REJECT_INVALID: banScore = 5; break; case RejectMessage.REJECT_OBSOLETE: banScore = BTCLoader.MAX_BAN_SCORE; break; default: banScore = 0; } if (banScore > 0) { synchronized(peer) { banScore += peer.getBanScore(); peer.setBanScore(banScore); if (banScore >= BTCLoader.MAX_BAN_SCORE) peer.setDisconnect(true); } } BTCLoader.networkHandler.wakeup(); } }