Search in sources :

Example 1 with Header

use of org.aion.p2p.Header in project aion by aionnetwork.

the class TaskWrite method run.

@Override
public void run() {
    // reset allocated buffer and clear messages if the channel is closed
    if (channelBuffer.isClosed.get()) {
        clearChannelBuffer();
        return;
    }
    if (channelBuffer.onWrite.compareAndSet(false, true)) {
        /*
             * @warning header set len (body len) before header encode
             */
        byte[] bodyBytes = msg.encode();
        int bodyLen = bodyBytes == null ? 0 : bodyBytes.length;
        Header h = msg.getHeader();
        h.setLen(bodyLen);
        byte[] headerBytes = h.encode();
        // print route
        // System.out.println("write " + h.getVer() + "-" + h.getCtrl() + "-" + h.getAction());
        ByteBuffer buf = ByteBuffer.allocate(headerBytes.length + bodyLen);
        buf.put(headerBytes);
        if (bodyBytes != null)
            buf.put(bodyBytes);
        buf.flip();
        try {
            while (buf.hasRemaining()) {
                sc.write(buf);
            }
        } catch (ClosedChannelException ex1) {
            if (showLog) {
                System.out.println("<p2p closed-channel-exception node=" + this.nodeShortId + ">");
            }
            channelBuffer.isClosed.set(true);
        } catch (IOException ex2) {
            if (showLog) {
                System.out.println("<p2p write-msg-io-exception node=" + this.nodeShortId + ">");
            }
        } finally {
            channelBuffer.onWrite.set(false);
            if (channelBuffer.isClosed.get()) {
                clearChannelBuffer();
            } else {
                Msg msg = channelBuffer.messages.poll();
                if (msg != null) {
                    // System.out.println("write " + h.getCtrl() + "-" + h.getAction());
                    workers.submit(new TaskWrite(workers, showLog, nodeShortId, sc, msg, channelBuffer, p2pMgr));
                }
            }
        }
    } else {
        // message may get dropped here when the message queue is full.
        channelBuffer.messages.offer(msg);
    }
}
Also used : Msg(org.aion.p2p.Msg) ClosedChannelException(java.nio.channels.ClosedChannelException) Header(org.aion.p2p.Header) IOException(java.io.IOException) ByteBuffer(java.nio.ByteBuffer)

Example 2 with Header

use of org.aion.p2p.Header in project aion by aionnetwork.

the class P2pMgr method process.

private void process(int nodeId, String nodeDisplayId, final Msg message, Dest peerList, long timestamp) {
    // Discard message after the timeout period has passed.
    long now = System.nanoTime();
    if (now - timestamp > WRITE_MSG_TIMEOUT) {
        p2pLOG.debug("timeout-msg to-node={} timestamp={}", nodeDisplayId, now);
    } else {
        INode node = null;
        switch(peerList) {
            case ACTIVE:
                node = nodeMgr.getActiveNode(nodeId);
                break;
            case INBOUND:
                node = nodeMgr.getInboundNode(nodeId);
                break;
            case OUTBOUND:
                node = nodeMgr.getOutboundNode(nodeId);
                break;
        }
        if (node == null) {
            p2pLOG.debug("msg-{} -> {} node-not-exist", peerList.name(), nodeDisplayId);
        } else {
            SelectionKey sk = node.getChannel().keyFor(selector);
            if (sk != null && sk.attachment() != null) {
                ChannelBuffer channelBuffer = (ChannelBuffer) sk.attachment();
                SocketChannel sc = node.getChannel();
                // reset allocated buffer and clear messages if the channel is closed
                if (channelBuffer.isClosed()) {
                    channelBuffer.refreshHeader();
                    channelBuffer.refreshBody();
                    this.dropActive(channelBuffer.getNodeIdHash(), "close-already");
                    return;
                } else {
                    try {
                        channelBuffer.lock.lock();
                        // @warning header set len (body len) before header encode
                        byte[] bodyBytes = message.encode();
                        int bodyLen = bodyBytes == null ? 0 : bodyBytes.length;
                        Header h = message.getHeader();
                        h.setLen(bodyLen);
                        byte[] headerBytes = h.encode();
                        p2pLOG.trace("write id:{} {}-{}-{}", nodeDisplayId, h.getVer(), h.getCtrl(), h.getAction());
                        ByteBuffer buf = ByteBuffer.allocate(headerBytes.length + bodyLen);
                        buf.put(headerBytes);
                        if (bodyBytes != null) {
                            buf.put(bodyBytes);
                        }
                        buf.flip();
                        long t1 = System.nanoTime(), t2;
                        int wrote = 0;
                        try {
                            do {
                                int result = sc.write(buf);
                                wrote += result;
                                if (result == 0) {
                                    // @Attention:  very important sleep , otherwise when NIO write buffer full,
                                    // without sleep will hangup this thread.
                                    Thread.sleep(0, 1);
                                }
                                t2 = System.nanoTime() - t1;
                            } while (buf.hasRemaining() && (t2 < MAX_BUFFER_WRITE_TIME));
                            if (t2 > MIN_TRACE_BUFFER_WRITE_TIME) {
                                p2pLOG.trace("msg write: id {} size {} time {} ms length {}", nodeDisplayId, wrote, t2, buf.array().length);
                            }
                        } catch (ClosedChannelException ex1) {
                            p2pLOG.debug("closed-channel-exception node=" + nodeDisplayId, ex1);
                            channelBuffer.setClosed();
                        } catch (IOException ex2) {
                            p2pLOG.debug("write-msg-io-exception node=" + nodeDisplayId + " headerBytes=" + headerBytes.length + " bodyLen=" + bodyLen + " time=" + (System.nanoTime() - t1) + "ns", ex2);
                            if (ex2.getMessage().equals("Broken pipe")) {
                                channelBuffer.setClosed();
                            }
                        } catch (InterruptedException e) {
                            p2pLOG.error("Interrupted while writing message to node=" + nodeDisplayId + ".", e);
                        }
                    } finally {
                        channelBuffer.lock.unlock();
                    }
                }
            }
        }
    }
}
Also used : SelectionKey(java.nio.channels.SelectionKey) SocketChannel(java.nio.channels.SocketChannel) ServerSocketChannel(java.nio.channels.ServerSocketChannel) ClosedChannelException(java.nio.channels.ClosedChannelException) INode(org.aion.p2p.INode) Header(org.aion.p2p.Header) IOException(java.io.IOException) ByteBuffer(java.nio.ByteBuffer)

Example 3 with Header

use of org.aion.p2p.Header in project aion by aionnetwork.

the class P2pMgr method run.

@Override
public void run() {
    try {
        selector = Selector.open();
        // IO-bounded threads get max-gain from the double of the availableProcessor number
        scheduledWorkers = Executors.newScheduledThreadPool(Math.min(32, 2 * Runtime.getRuntime().availableProcessors()));
        inboundExecutor = Executors.newSingleThreadScheduledExecutor();
        tcpServer = ServerSocketChannel.open();
        tcpServer.configureBlocking(false);
        tcpServer.socket().setReuseAddress(true);
        /*
             * Bigger RECV_BUFFER and BACKLOG can have a better socket read/write tolerance, can be a advanced p2p settings in the config file.
             */
        tcpServer.socket().setReceiveBufferSize(SOCKET_RECV_BUFFER);
        try {
            tcpServer.socket().bind(new InetSocketAddress(Node.ipBytesToStr(selfIp), selfPort), SOCKET_BACKLOG);
        } catch (IOException e) {
            p2pLOG.error("Failed to connect to Socket Address: " + Node.ipBytesToStr(selfIp) + ":" + selfPort + ", please check your ip and port configration!", e);
        }
        tcpServer.register(selector, SelectionKey.OP_ACCEPT);
        inboundExecutor.scheduleWithFixedDelay(this::checkSelector, DELAY_SELECT, DELAY_SELECT, TimeUnit.MILLISECONDS);
        if (p2pLOG.isDebugEnabled()) {
            this.handlers.forEach((route, callbacks) -> {
                Handler handler = callbacks.get(0);
                Header h = handler.getHeader();
                p2pLOG.debug("handler route={} v-c-a={}-{}-{} name={}", route, h.getVer(), h.getCtrl(), h.getAction(), handler.getClass().getSimpleName());
            });
        }
        if (upnpEnable) {
            scheduledWorkers.scheduleWithFixedDelay(new TaskUPnPManager(p2pLOG, selfPort), 1, PERIOD_UPNP_PORT_MAPPING, TimeUnit.MILLISECONDS);
        }
        if (p2pLOG.isInfoEnabled()) {
            scheduledWorkers.scheduleWithFixedDelay(() -> {
                Thread.currentThread().setName("p2p-status");
                p2pLOG.info(nodeMgr.dumpNodeInfo(selfShortId, p2pLOG.isDebugEnabled()));
            }, DELAY_SHOW_P2P_STATUS, DELAY_SHOW_P2P_STATUS, TimeUnit.SECONDS);
        }
        if (!syncSeedsOnly) {
            scheduledWorkers.scheduleWithFixedDelay(() -> {
                Thread.currentThread().setName("p2p-reqNodes");
                INode node = getRandom();
                if (node != null) {
                    p2pLOG.trace("TaskRequestActiveNodes: {}", node.toString());
                    send(node.getIdHash(), node.getIdShort(), cachedReqActiveNodesMsg);
                }
            }, 5 * DELAY_REQUEST_ACTIVE_NODES, DELAY_REQUEST_ACTIVE_NODES, TimeUnit.SECONDS);
        }
        scheduledWorkers.scheduleWithFixedDelay(() -> {
            Thread.currentThread().setName("p2p-clear");
            nodeMgr.timeoutCheck(System.currentTimeMillis());
        }, DELAY_CLEAR_PEERS, DELAY_CLEAR_PEERS, TimeUnit.SECONDS);
        scheduledWorkers.scheduleWithFixedDelay(() -> connectPeers(), DELAY_CONNECT_OUTBOUND, DELAY_CONNECT_OUTBOUND, TimeUnit.SECONDS);
    } catch (SocketException e) {
        p2pLOG.error("tcp-server-socket-exception.", e);
    } catch (IOException e) {
        p2pLOG.error("tcp-server-io-exception.", e);
    }
}
Also used : SocketException(java.net.SocketException) INode(org.aion.p2p.INode) Header(org.aion.p2p.Header) TaskUPnPManager(org.aion.p2p.impl.TaskUPnPManager) InetSocketAddress(java.net.InetSocketAddress) Handler(org.aion.p2p.Handler) IOException(java.io.IOException)

Example 4 with Header

use of org.aion.p2p.Header in project aion by aionnetwork.

the class P2pMgr method handleMessage.

private void handleMessage(SelectionKey sk, ChannelBuffer cb) {
    Header h = cb.getHeader();
    byte[] bodyBytes = cb.body;
    cb.refreshHeader();
    cb.refreshBody();
    int maxRequestsPerSecond = 0;
    // TODO: refactor to remove knowledge of sync message types
    if (h.getCtrl() == CTRL_SYNC && h.getAction() == ACT_BROADCAST_BLOCK) {
        maxRequestsPerSecond = P2pConstant.READ_MAX_RATE;
    } else {
        maxRequestsPerSecond = P2pConstant.READ_MAX_RATE_TXBC;
    }
    boolean underRC = cb.shouldRoute(h.getRoute(), maxRequestsPerSecond);
    if (!underRC) {
        p2pLOG.debug("over-called-route={}-{}-{} calls={} node={}", h.getVer(), h.getCtrl(), h.getAction(), cb.getRouteCount(h.getRoute()).count, cb.getDisplayId());
        return;
    }
    switch(h.getVer()) {
        case Ver.V0:
            switch(h.getCtrl()) {
                case Ctrl.NET:
                    try {
                        handleP2pMessage(sk, h.getAction(), bodyBytes);
                    } catch (Exception ex) {
                        p2pLOG.debug("handle-p2p-msg error.", ex);
                    }
                    break;
                case Ctrl.SYNC:
                    if (!handlers.containsKey(h.getRoute())) {
                        p2pLOG.debug("unregistered-route={}-{}-{} node={}", h.getVer(), h.getCtrl(), h.getAction(), cb.getDisplayId());
                        return;
                    }
                    handleKernelMessage(cb.getNodeIdHash(), h.getRoute(), bodyBytes);
                    break;
                default:
                    p2pLOG.debug("invalid-route={}-{}-{} node={}", h.getVer(), h.getCtrl(), h.getAction(), cb.getDisplayId());
                    break;
            }
            break;
        default:
            p2pLOG.debug("unhandled-ver={} node={}", h.getVer(), cb.getDisplayId());
            break;
    }
}
Also used : Header(org.aion.p2p.Header) SocketException(java.net.SocketException) ClosedChannelException(java.nio.channels.ClosedChannelException) IOException(java.io.IOException)

Example 5 with Header

use of org.aion.p2p.Header in project aion by aionnetwork.

the class P2pMgr method register.

@Override
public void register(final List<Handler> _cbs) {
    for (Handler _cb : _cbs) {
        Header h = _cb.getHeader();
        short ver = h.getVer();
        byte ctrl = h.getCtrl();
        if (Ver.filter(ver) != Ver.UNKNOWN && Ctrl.filter(ctrl) != Ctrl.UNKNOWN) {
            versions.add(ver);
            int route = h.getRoute();
            List<Handler> routeHandlers = handlers.get(route);
            if (routeHandlers == null) {
                routeHandlers = new ArrayList<>();
                routeHandlers.add(_cb);
                handlers.put(route, routeHandlers);
            } else {
                routeHandlers.add(_cb);
            }
        }
    }
    cachedReqHandshake1 = new ReqHandshake1(selfNodeId, selfChainId, selfIp, selfPort, selfRevision.getBytes(), new ArrayList<>(versions));
}
Also used : Header(org.aion.p2p.Header) ReqHandshake1(org.aion.p2p.impl.zero.msg.ReqHandshake1) ArrayList(java.util.ArrayList) Handler(org.aion.p2p.Handler)

Aggregations

Header (org.aion.p2p.Header)6 IOException (java.io.IOException)4 ByteBuffer (java.nio.ByteBuffer)3 ClosedChannelException (java.nio.channels.ClosedChannelException)3 SocketException (java.net.SocketException)2 Handler (org.aion.p2p.Handler)2 INode (org.aion.p2p.INode)2 InetSocketAddress (java.net.InetSocketAddress)1 SelectionKey (java.nio.channels.SelectionKey)1 ServerSocketChannel (java.nio.channels.ServerSocketChannel)1 SocketChannel (java.nio.channels.SocketChannel)1 ArrayList (java.util.ArrayList)1 Msg (org.aion.p2p.Msg)1 TaskUPnPManager (org.aion.p2p.impl.TaskUPnPManager)1 ReqHandshake1 (org.aion.p2p.impl.zero.msg.ReqHandshake1)1