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);
}
}
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();
}
}
}
}
}
}
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);
}
}
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;
}
}
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));
}
Aggregations