public String getLabel() { return "Network Node " + myInfo.getNumber() + ": "; }
public int getNumber() { return myInfo.getNumber(); }
/** * When handshake completed, sessionReader moves from candidates list to working readers list. * @param sessionReader */ private void acceptSessionReaderCandidate(SessionReader sessionReader) { sessionReaders.put(sessionReader.remoteNodeInfo.getNumber(), sessionReader); sessionReaderCandidates.remove(sessionReader.remoteNodeInfo.getNumber()); }
@Override public Thread newThread(Runnable r) { Thread thread = new Thread(threadGroup,r); thread.setName("node-"+myInfo.getNumber()+"-worker"); return thread; } });
@Override public Thread newThread(Runnable r) { Thread thread = new Thread(threadGroup,r); thread.setName("low-prio-node-"+myInfo.getNumber()+"-worker"); thread.setPriority((Thread.NORM_PRIORITY+Thread.MIN_PRIORITY)/2); return thread; } });
@Override public String toString() { return "[" + dataFormat.format(new Date()) + "] Node(" + myInfo.getNumber() + ") "; }
public void addNode(NodeInfo n) { if( n != null ) { byNumber.put(n.getNumber(), n); byName.put(n.getName(), n); } }
public void removeNode(NodeInfo nodeInfo) { byNumber.remove(nodeInfo.getNumber()); byName.remove(nodeInfo.getName()); } }
/** * Checks time of active handshake procedures and restarts them if time is up {@link UDPAdapter#HANDSHAKE_TIMEOUT_MILLIS} * @param s session * @param now pass here Instant.now() */ private void restartHandshakeIfNeeded(Session s, Instant now) { if (s.state.get() == Session.STATE_HANDSHAKE) { if (s.handshakeExpiresAt.isBefore(now)) { report(logLabel, ()->"handshaking with nodeId="+s.remoteNodeInfo.getNumber()+" is timed out, restart", VerboseLevel.BASE); s.handshakeStep.set(Session.HANDSHAKE_STEP_WAIT_FOR_WELCOME); s.handshakeExpiresAt = now.plusMillis(HANDSHAKE_TIMEOUT_MILLIS); sendHello(s); } } }
/** * Each adapter will try to send blocks until have got special {@link Packet} with type {@link PacketTypes#ACK}, * that means receiver have got block. So when we got packet and all is ok - call this method. * @param sessionReader is {@link SessionReader} in which sending is. * @param packetId is id of packet we have got. */ private void sendAck(SessionReader sessionReader, Integer packetId) throws EncryptionError { report(logLabel, ()->"send ack to "+sessionReader.remoteNodeInfo.getNumber(), VerboseLevel.DETAILED); Packet packet = new Packet(0, myNodeInfo.getNumber(), sessionReader.remoteNodeInfo.getNumber(), PacketTypes.ACK, new SymmetricKey(sessionReader.sessionKey.getKey()).etaEncrypt(Boss.pack(packetId))); sendPacket(sessionReader.remoteNodeInfo, packet); }
/** * Creates {@link Packet} of type {@link PacketTypes#DATA} and sends it to network, initiates retransmission. * It is normal data sending procedure when {@link Session} with remote node is already established. * @param session {@link Session} with remote node * @param payload data to send */ private void sendPayload(Session session, byte[] payload) { byte[] dataToSend = preparePayloadForSession(session.sessionKey, payload); Packet packet = new Packet(getNextPacketId(), myNodeInfo.getNumber(), session.remoteNodeInfo.getNumber(), PacketTypes.DATA, dataToSend); sendPacket(session.remoteNodeInfo, packet); session.addPacketToRetransmitMap(packet.packetId, packet, payload); }
/** * ACK packets are used only for respond to DATA packets. Retransmission of handshake's packet types stops on each * next handshake step. But last step need to be ACK-ed. For this used {@link PacketTypes#SESSION_ACK} packet. * @param session is {@link Session} in which sending is. * @throws EncryptionError */ private void sendSessionAck(Session session) throws EncryptionError { report(logLabel, ()->"send session_ack to "+session.remoteNodeInfo.getNumber(), VerboseLevel.BASE); Packet packet = new Packet(0, myNodeInfo.getNumber(), session.remoteNodeInfo.getNumber(), PacketTypes.SESSION_ACK, new SymmetricKey(session.sessionKey.getKey()).etaEncrypt(Do.randomBytes(32))); sendPacket(session.remoteNodeInfo, packet); }
@Override public void removeNode(NodeInfo nodeInfo) { try (PooledDb db = dbPool.db()) { String sqlText = "delete from config where node_number = ?;"; try ( PreparedStatement statement = db.statementReturningKeys(sqlText, nodeInfo.getNumber()) ) { db.updateWithStatement(statement); } catch (Exception e) { e.printStackTrace(); throw e; } } catch (SQLException se) { se.printStackTrace(); throw new Failure("remove node failed:" + se); } catch (Exception e) { e.printStackTrace(); } }
@Override synchronized public void send(NodeInfo destination, byte[] payload) throws InterruptedException { report(logLabel, () -> "send to "+destination.getNumber()+", isActive: "+socketListenThread.isActive.get(), VerboseLevel.DETAILED); if (!socketListenThread.isActive.get()) return; Session session = getOrCreateSession(destination); if (session.state.get() == Session.STATE_HANDSHAKE) { session.addPayloadToOutputQueue(destination, payload); } else { if (session.retransmitMap.size() > MAX_RETRANSMIT_QUEUE_SIZE) session.addPayloadToOutputQueue(destination, payload); else sendPayload(session, payload); } }
private final byte[] packNotifications(NodeInfo from, Collection<Notification> notifications) { Boss.Writer w = new Boss.Writer(); try { w.write(1) // packet type code .write(from.getNumber()) // from number .write(notifications.size()); // count notifications notifications.forEach(n -> { try { Notification.write(w, n); } catch (IOException e) { throw new RuntimeException("notificaiton pack failure", e); } }); return w.toByteArray(); } catch (IOException e) { throw new RuntimeException("notificaiton pack failure", e); } }
protected void sendHello(NodeInfo myNodeInfo, NodeInfo destination, UDPAdapter udpAdapter, DatagramSocket socket) throws InterruptedException { // System.out.println(">> send froud from " + myNodeInfo.getNumber() + " to " + destination.getNumber()); Binder binder = Binder.fromKeysValues( "data", myNodeInfo.getNumber() ); UDPAdapter.Packet packet = udpAdapter.createTestPacket( new Random().nextInt(Integer.MAX_VALUE), myNodeInfo.getNumber(), destination.getNumber(), UDPAdapter.PacketTypes.HELLO, Boss.pack(binder)); sendBlock(packet, socket, destination); }
/** * This is first step of creation and installation of the session. * @param session is {@link Session} in which sending is. */ private void sendHello(Session session) { try { report(logLabel, () -> "send hello to " + session.remoteNodeInfo.getNumber(), VerboseLevel.BASE); byte[] helloNonce = Do.randomBytes(64); Packet packet = new Packet(getNextPacketId(), myNodeInfo.getNumber(), session.remoteNodeInfo.getNumber(), PacketTypes.HELLO, new PublicKey(session.remoteNodeInfo.getPublicKey().pack()).encrypt(helloNonce)); sendPacket(session.remoteNodeInfo, packet); session.addPacketToRetransmitMap(packet.packetId, packet, helloNonce); } catch (EncryptionError e) { callErrorCallbacks("(sendHello) EncryptionError: " + e); } }
protected void sendWelcome(NodeInfo myNodeInfo, NodeInfo destination, UDPAdapter udpAdapter, DatagramSocket socket) throws Exception { byte[] payload = new PublicKey(destination.getPublicKey().pack()).encrypt(Do.randomBytes(64)); UDPAdapter.Packet packet = udpAdapter.createTestPacket( new Random().nextInt(Integer.MAX_VALUE), myNodeInfo.getNumber(), destination.getNumber(), UDPAdapter.PacketTypes.WELCOME, payload); sendBlock(packet, socket, destination); }
protected void sendDataGarbage(NodeInfo myNodeInfo, NodeInfo destination, UDPAdapter udpAdapter, DatagramSocket socket) throws Exception { byte[] data = new PublicKey(destination.getPublicKey().pack()).encrypt(Do.randomBytes(64)); byte[] crc32 = new Crc32().digest(data); byte[] payload = new byte[data.length + crc32.length]; System.arraycopy(data, 0, payload, 0, data.length); System.arraycopy(crc32, 0, payload, data.length, crc32.length); UDPAdapter.Packet packet = udpAdapter.createTestPacket( new Random().nextInt(Integer.MAX_VALUE), myNodeInfo.getNumber(), destination.getNumber(), UDPAdapter.PacketTypes.DATA, payload); sendBlock(packet, socket, destination); }
public void obtainNotification(CallbackNotification notification) { node.report(DatagramAdapter.VerboseLevel.DETAILED, "Notify callback ", notification.getId().toBase64String(), " type ", notification.getType().name(), " from node ", notification.getFrom().getName()); if (notification.getType() == CallbackNotification.CallbackNotificationType.COMPLETED) { if (checkCallbackSignature(notification.getSignature())) complete(); } else if (notification.getType() == CallbackNotification.CallbackNotificationType.NOT_RESPONDING) { addNodeToSended(notification.getFrom().getNumber()); checkForComplete(); } }