Removed BucketEntry in favor of NodeIdentifier, buckets still not correct
This commit is contained in:
parent
6a23d56e2d
commit
036b77cf2d
42
ws2012/P2P/uebungen/8/src/CLI.java
Normal file
42
ws2012/P2P/uebungen/8/src/CLI.java
Normal file
@ -0,0 +1,42 @@
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.logging.LogManager;
|
||||
|
||||
import node.Node;
|
||||
import node.NodeIdentifier;
|
||||
|
||||
public class CLI {
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
System.setProperty("java.util.logging.config.file",
|
||||
"logging.properties");
|
||||
|
||||
try {
|
||||
LogManager.getLogManager().readConfiguration();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
Node node = new Node();
|
||||
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
|
||||
String s;
|
||||
while ((s = in.readLine()) != null && s.length() != 0) {
|
||||
String[] splitted = s.split(" ");
|
||||
|
||||
String cmd = splitted[0];
|
||||
|
||||
switch (cmd) {
|
||||
case "status":
|
||||
for (NodeIdentifier id : node.getNeighbors()) {
|
||||
System.out.println(id);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
System.out.println("Unknown command.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5,65 +5,70 @@ import java.util.BitSet;
|
||||
import java.util.Random;
|
||||
|
||||
public class Identifier {
|
||||
private static Random random = new Random(System.currentTimeMillis());
|
||||
private static Random random = new Random(System.currentTimeMillis());
|
||||
|
||||
private BitSet bits;
|
||||
protected BitSet bits;
|
||||
|
||||
public Identifier(byte[] bytes) {
|
||||
this.bits = BitSet.valueOf(bytes);
|
||||
}
|
||||
public Identifier(byte[] bytes) {
|
||||
this.bits = BitSet.valueOf(bytes);
|
||||
}
|
||||
|
||||
private Identifier(BitSet bits) {
|
||||
this.bits = bits;
|
||||
}
|
||||
this.bits = bits;
|
||||
}
|
||||
|
||||
public static Identifier getStaticIdentifier() {
|
||||
BitSet middle = new BitSet(Node.ID_BITS);
|
||||
BitSet middle = new BitSet(Node.ID_BITS);
|
||||
middle.set(Node.ID_BITS - 1);
|
||||
return new Identifier(middle);
|
||||
}
|
||||
}
|
||||
|
||||
public static Identifier getRandomIdentifier() {
|
||||
BitSet bits = new BitSet(Node.ID_BITS);
|
||||
public static Identifier getRandomIdentifier() {
|
||||
BitSet bits = new BitSet(Node.ID_BITS);
|
||||
|
||||
for (int i = 0; i < Node.ID_BITS; i++) {
|
||||
double threshold = random.nextGaussian();
|
||||
if (threshold > 0) {
|
||||
bits.set(i);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < Node.ID_BITS; i++) {
|
||||
double threshold = random.nextGaussian();
|
||||
if (threshold > 0) {
|
||||
bits.set(i);
|
||||
}
|
||||
}
|
||||
|
||||
return new Identifier(bits);
|
||||
}
|
||||
return new Identifier(bits);
|
||||
}
|
||||
|
||||
public BitSet distanceTo(Identifier otherID) {
|
||||
BitSet distance = (BitSet) bits.clone();
|
||||
distance.xor(otherID.getBitSet());
|
||||
return distance;
|
||||
}
|
||||
public BigInteger distanceTo(Identifier otherID) {
|
||||
BitSet distance = (BitSet) bits.clone();
|
||||
distance.xor(otherID.getBitSet());
|
||||
return new BigInteger(1, distance.toByteArray());
|
||||
}
|
||||
|
||||
public boolean isBitSetAt(int index) {
|
||||
return bits.get(index);
|
||||
}
|
||||
public boolean isBitSetAt(int index) {
|
||||
return bits.get(index);
|
||||
}
|
||||
|
||||
public byte[] getBytes() {
|
||||
return bits.toByteArray();
|
||||
}
|
||||
public byte[] getBytes() {
|
||||
return bits.toByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof Identifier)) {
|
||||
return false;
|
||||
} else {
|
||||
return bits.equals(((Identifier) o).getBitSet());
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof Identifier)) {
|
||||
return false;
|
||||
} else {
|
||||
return bits.equals(((Identifier) o).getBitSet());
|
||||
}
|
||||
}
|
||||
|
||||
public BitSet getBitSet() {
|
||||
return bits;
|
||||
}
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return toString().hashCode();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return new BigInteger(bits.toByteArray()).toString();
|
||||
}
|
||||
private BitSet getBitSet() {
|
||||
return bits;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return new BigInteger(1, bits.toByteArray()).toString();
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,178 +14,182 @@ import java.util.logging.Logger;
|
||||
|
||||
import message.Ack;
|
||||
import message.MessageType;
|
||||
import routingtable.BucketEntry;
|
||||
import routingtable.RoutingTable;
|
||||
|
||||
public class Node {
|
||||
/**
|
||||
* Size of ID space
|
||||
*/
|
||||
public static final int ID_BITS = 8;
|
||||
/**
|
||||
* Size of ID space (has to be a multiple of 8)
|
||||
*/
|
||||
public static final int ID_BITS = 8;
|
||||
|
||||
/**
|
||||
* The bucket size
|
||||
*/
|
||||
private static final int BUCKET_SIZE = 2;
|
||||
/**
|
||||
* The bucket size
|
||||
*/
|
||||
public static final int BUCKET_SIZE = 2;
|
||||
|
||||
/**
|
||||
* The first node is always spawned on port 50000
|
||||
*/
|
||||
private static final int INITIAL_PORT = 50000;
|
||||
/**
|
||||
* The first node is always spawned on port 50000
|
||||
*/
|
||||
private static final int INITIAL_PORT = 50000;
|
||||
private static final Identifier INITIAL_ID = Identifier
|
||||
.getStaticIdentifier();
|
||||
|
||||
private final static Logger LOGGER = Logger.getLogger(Node.class.getName());
|
||||
private static final int _BUFFER_SIZE = 512;
|
||||
|
||||
private InetSocketAddress address;
|
||||
private DatagramChannel channel;
|
||||
private final static Logger LOGGER = Logger.getLogger(Node.class.getName());
|
||||
|
||||
private Map<Integer, Ack> acks = new HashMap<Integer, Ack>();
|
||||
private InetSocketAddress address;
|
||||
private DatagramChannel channel;
|
||||
|
||||
private Thread thread;
|
||||
private UDPHandler udpListen;
|
||||
private Map<Integer, Ack> acks = new HashMap<Integer, Ack>();
|
||||
|
||||
private Identifier nodeID = Identifier.getRandomIdentifier();
|
||||
private Thread thread;
|
||||
private UDPHandler udpListen;
|
||||
|
||||
private RoutingTable rt = new RoutingTable(BUCKET_SIZE);
|
||||
private Identifier nodeID = Identifier.getRandomIdentifier();
|
||||
|
||||
public Node() {
|
||||
System.setProperty("java.net.preferIPv4Stack", "true");
|
||||
private RoutingTable rt = new RoutingTable(BUCKET_SIZE);
|
||||
|
||||
try {
|
||||
channel = DatagramChannel.open();
|
||||
public Node() {
|
||||
System.setProperty("java.net.preferIPv4Stack", "true");
|
||||
|
||||
try {
|
||||
address = new InetSocketAddress("localhost", INITIAL_PORT);
|
||||
channel.socket().bind(address);
|
||||
try {
|
||||
channel = DatagramChannel.open();
|
||||
|
||||
this.nodeID = INITIAL_ID;
|
||||
} catch (SocketException e) {
|
||||
// Port 9999 is already bound -> pick a random port
|
||||
channel.socket().bind(new InetSocketAddress("localhost", 0));
|
||||
address = (InetSocketAddress) channel.getLocalAddress();
|
||||
}
|
||||
try {
|
||||
address = new InetSocketAddress("localhost", INITIAL_PORT);
|
||||
channel.socket().bind(address);
|
||||
|
||||
channel.configureBlocking(false);
|
||||
this.nodeID = INITIAL_ID;
|
||||
} catch (SocketException e) {
|
||||
// Port 9999 is already bound -> pick a random port
|
||||
channel.socket().bind(new InetSocketAddress("localhost", 0));
|
||||
address = (InetSocketAddress) channel.getLocalAddress();
|
||||
}
|
||||
|
||||
udpListen = new UDPHandler(this);
|
||||
thread = new Thread(udpListen);
|
||||
thread.start();
|
||||
channel.configureBlocking(false);
|
||||
|
||||
LOGGER.log(Level.INFO, "Initialized node {0} on {1}", new Object[] {
|
||||
getName(), address.toString() });
|
||||
udpListen = new UDPHandler(this);
|
||||
thread = new Thread(udpListen);
|
||||
thread.start();
|
||||
|
||||
if (address.getPort() != INITIAL_PORT) {
|
||||
joinNetworkVia(
|
||||
new InetSocketAddress("localhost", INITIAL_PORT),
|
||||
INITIAL_ID);
|
||||
}
|
||||
LOGGER.log(Level.INFO, "Initialized node {0} on {1}", new Object[] {
|
||||
getName(), address.toString() });
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (address.getPort() != INITIAL_PORT) {
|
||||
joinNetworkVia(new NodeIdentifier(INITIAL_ID.getBytes(),
|
||||
new InetSocketAddress("127.0.0.1", INITIAL_PORT)));
|
||||
}
|
||||
|
||||
private void joinNetworkVia(InetSocketAddress receiver, Identifier id) {
|
||||
LOGGER.log(Level.INFO, "Trying to join network via node {0} ({1})",
|
||||
new Object[] { id, receiver });
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
rt.update(id, receiver);
|
||||
// Send a FIND_NODE. The node to find is my own id (bootstrapping...)
|
||||
sendFindNode(receiver, nodeID);
|
||||
}
|
||||
private void joinNetworkVia(NodeIdentifier receiver) {
|
||||
LOGGER.log(Level.INFO, "Trying to join network via node {0}",
|
||||
new Object[] { receiver });
|
||||
|
||||
void sendFindNode(InetSocketAddress receiver, Identifier idToFind) {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(5 + 4 + 4);
|
||||
rt.update(receiver);
|
||||
// Send a FIND_NODE. The node to find is my own id (bootstrapping...)
|
||||
sendFindNode(receiver, nodeID);
|
||||
}
|
||||
|
||||
Identifier rpc_id = Identifier.getRandomIdentifier();
|
||||
void sendFindNode(NodeIdentifier receiver, Identifier idToFind) {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(_BUFFER_SIZE);
|
||||
|
||||
buffer.put(MessageType.FIND_NODE);
|
||||
buffer.put(nodeID.getBytes());
|
||||
buffer.put(rpc_id.getBytes());
|
||||
buffer.put(idToFind.getBytes());
|
||||
Identifier rpc_id = Identifier.getRandomIdentifier();
|
||||
|
||||
if (send(buffer, receiver)) {
|
||||
LOGGER.log(Level.INFO, "Sending [FIND_NODE {0}] to node {1}",
|
||||
new Object[] { idToFind, receiver });
|
||||
}
|
||||
}
|
||||
buffer.put(MessageType.FIND_NODE);
|
||||
buffer.put(nodeID.getBytes());
|
||||
buffer.put(rpc_id.getBytes());
|
||||
buffer.put(idToFind.getBytes());
|
||||
|
||||
void sendClosestNodesTo(InetSocketAddress receiver, Identifier receiverId,
|
||||
Identifier idToFind, Identifier rpc_id) {
|
||||
if (send(buffer, receiver.getAddress())) {
|
||||
LOGGER.log(Level.INFO, "Sending [FIND_NODE {0}] to node {1}",
|
||||
new Object[] { idToFind, receiver });
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: how big?!
|
||||
ByteBuffer buffer = ByteBuffer.allocate(512);
|
||||
void sendClosestNodesTo(NodeIdentifier receiver, Identifier idToFind,
|
||||
Identifier rpc_id) {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(_BUFFER_SIZE);
|
||||
|
||||
buffer.put(MessageType.NODES);
|
||||
buffer.put(nodeID.getBytes());
|
||||
buffer.put(rpc_id.getBytes());
|
||||
buffer.put(MessageType.NODES);
|
||||
buffer.put(nodeID.getBytes());
|
||||
buffer.put(rpc_id.getBytes());
|
||||
|
||||
Set<BucketEntry> entries = rt.getClosestNodesTo(idToFind);
|
||||
for (BucketEntry e : entries) {
|
||||
if (!receiverId.equals(e.id))
|
||||
buffer.put(e.getBytes());
|
||||
}
|
||||
Set<NodeIdentifier> entries = rt.getClosestNodesTo(idToFind);
|
||||
for (NodeIdentifier id : entries) {
|
||||
if (!receiver.equals(id)) {
|
||||
buffer.put(id.getTripleAsBytes());
|
||||
}
|
||||
}
|
||||
|
||||
if (send(buffer, receiver)) {
|
||||
LOGGER.log(Level.INFO, "Sending [NODES {0}] to node {1}.",
|
||||
new Object[] { idToFind, receiverId });
|
||||
}
|
||||
}
|
||||
if (send(buffer, receiver.getAddress())) {
|
||||
LOGGER.log(Level.INFO,
|
||||
"Sending {0} nodes to to node {1} [FIND_NODE {2}].",
|
||||
new Object[] { entries.size(), receiver, idToFind });
|
||||
}
|
||||
}
|
||||
|
||||
private boolean send(ByteBuffer buffer, InetSocketAddress to) {
|
||||
buffer.flip();
|
||||
try {
|
||||
channel.send(buffer, to);
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
private boolean send(ByteBuffer buffer, InetSocketAddress to) {
|
||||
buffer.flip();
|
||||
try {
|
||||
channel.send(buffer, to);
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return nodeID.toString();
|
||||
}
|
||||
public String getName() {
|
||||
return nodeID.toString();
|
||||
}
|
||||
|
||||
public boolean hasAcks() {
|
||||
return !acks.isEmpty();
|
||||
}
|
||||
public boolean hasAcks() {
|
||||
return !acks.isEmpty();
|
||||
}
|
||||
|
||||
protected boolean hasAck(int ack_id) {
|
||||
return acks.containsKey(ack_id);
|
||||
}
|
||||
protected boolean hasAck(int ack_id) {
|
||||
return acks.containsKey(ack_id);
|
||||
}
|
||||
|
||||
protected Ack getAck(int ack_id) {
|
||||
return acks.get(ack_id);
|
||||
}
|
||||
protected Ack getAck(int ack_id) {
|
||||
return acks.get(ack_id);
|
||||
}
|
||||
|
||||
protected void removeAck(int ack_id) {
|
||||
acks.remove(ack_id).setReceived();
|
||||
}
|
||||
protected void removeAck(int ack_id) {
|
||||
acks.remove(ack_id).setReceived();
|
||||
}
|
||||
|
||||
public DatagramChannel getChannel() {
|
||||
return channel;
|
||||
}
|
||||
public DatagramChannel getChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
public void updateBuckets(Identifier id, InetSocketAddress from) {
|
||||
rt.update(id, from);
|
||||
}
|
||||
public void updateBuckets(NodeIdentifier id) {
|
||||
rt.update(id);
|
||||
}
|
||||
|
||||
public Identifier getID() {
|
||||
return nodeID;
|
||||
}
|
||||
public Identifier getID() {
|
||||
return nodeID;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.setProperty("java.util.logging.config.file",
|
||||
"logging.properties");
|
||||
public Set<NodeIdentifier> getNeighbors() {
|
||||
return rt.getEntries();
|
||||
}
|
||||
|
||||
try {
|
||||
LogManager.getLogManager().readConfiguration();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
public static void main(String[] args) {
|
||||
System.setProperty("java.util.logging.config.file",
|
||||
"logging.properties");
|
||||
|
||||
new Node();
|
||||
}
|
||||
try {
|
||||
LogManager.getLogManager().readConfiguration();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
new Node();
|
||||
}
|
||||
}
|
||||
|
||||
35
ws2012/P2P/uebungen/8/src/node/NodeIdentifier.java
Normal file
35
ws2012/P2P/uebungen/8/src/node/NodeIdentifier.java
Normal file
@ -0,0 +1,35 @@
|
||||
package node;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import util.BufferUtil;
|
||||
|
||||
public class NodeIdentifier extends Identifier {
|
||||
|
||||
private InetSocketAddress address;
|
||||
|
||||
public NodeIdentifier(byte[] bytes, InetSocketAddress address) {
|
||||
super(bytes);
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public byte[] getTripleAsBytes() {
|
||||
ByteBuffer result = ByteBuffer.allocate(8 + (Node.ID_BITS / 8));
|
||||
|
||||
result.put(BufferUtil.addrToBytes(address));
|
||||
result.put(bits.toByteArray());
|
||||
return result.array();
|
||||
}
|
||||
|
||||
public InetSocketAddress getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return new BigInteger(1, bits.toByteArray()).toString() + " ("
|
||||
+ address.toString() + ")";
|
||||
}
|
||||
|
||||
}
|
||||
@ -3,143 +3,146 @@ package node;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import message.MessageType;
|
||||
import routingtable.BucketEntry;
|
||||
|
||||
public class UDPHandler implements Runnable {
|
||||
private final static Logger LOGGER = Logger.getLogger(UDPHandler.class
|
||||
.getName());
|
||||
private final static Logger LOGGER = Logger.getLogger(UDPHandler.class
|
||||
.getName());
|
||||
|
||||
public static final int BUF_SIZE = 512;
|
||||
public static final int BUF_SIZE = 512;
|
||||
|
||||
private volatile boolean running = true;
|
||||
private ByteBuffer buffer = ByteBuffer.allocate(BUF_SIZE);
|
||||
private volatile boolean running = true;
|
||||
private ByteBuffer buffer = ByteBuffer.allocate(BUF_SIZE);
|
||||
|
||||
private Node node;
|
||||
private Node node;
|
||||
|
||||
public UDPHandler(Node node) {
|
||||
this.node = node;
|
||||
}
|
||||
public UDPHandler(Node node) {
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the buffer of this UDPHandler as is and tries to read an IP address
|
||||
* (4 bytes and 1 int) from it. If there is no/incomplete or wrong data,
|
||||
* this will fail.
|
||||
*
|
||||
* @return the address that has been read
|
||||
*/
|
||||
private InetSocketAddress getIPFromBuffer() {
|
||||
StringBuilder theAddr = new StringBuilder();
|
||||
// Read 4 Bytes and 1 Integer = 1 IP address
|
||||
for (int i = 0; i < 4; i++) {
|
||||
theAddr.append(buffer.get());
|
||||
if (i < 3) {
|
||||
theAddr.append(".");
|
||||
}
|
||||
}
|
||||
int port = buffer.getInt();
|
||||
return new InetSocketAddress(theAddr.toString(), port);
|
||||
}
|
||||
/**
|
||||
* Takes the buffer of this UDPHandler as is and tries to read an IP address
|
||||
* (4 bytes and 1 int) from it. If there is no/incomplete or wrong data,
|
||||
* this will fail.
|
||||
*
|
||||
* @return the address that has been read
|
||||
*/
|
||||
private InetSocketAddress getIPFromBuffer() {
|
||||
StringBuilder theAddr = new StringBuilder();
|
||||
// Read 4 Bytes and 1 Integer = 1 IP address
|
||||
for (int i = 0; i < 4; i++) {
|
||||
theAddr.append(buffer.get());
|
||||
if (i < 3) {
|
||||
theAddr.append(".");
|
||||
}
|
||||
}
|
||||
int port = buffer.getInt();
|
||||
return new InetSocketAddress(theAddr.toString(), port);
|
||||
}
|
||||
|
||||
private Identifier getIDFromBuffer() {
|
||||
int numBytes = Node.ID_BITS / 8;
|
||||
byte[] result = new byte[numBytes];
|
||||
private Identifier getIDFromBuffer() {
|
||||
int numBytes = Node.ID_BITS / 8;
|
||||
byte[] result = new byte[numBytes];
|
||||
for (int i = 0; i < numBytes; i++) {
|
||||
result[i] = buffer.get();
|
||||
}
|
||||
return new Identifier(result);
|
||||
}
|
||||
|
||||
for (int i = 0; i < numBytes; i++) {
|
||||
result[i] = buffer.get();
|
||||
}
|
||||
private NodeIdentifier getNodeTripleFromBuffer() {
|
||||
InetSocketAddress address = getIPFromBuffer();
|
||||
|
||||
return new Identifier(result);
|
||||
}
|
||||
int numBytes = Node.ID_BITS / 8;
|
||||
byte[] result = new byte[numBytes];
|
||||
for (int i = 0; i < numBytes; i++) {
|
||||
result[i] = buffer.get();
|
||||
}
|
||||
return new NodeIdentifier(result, address);
|
||||
}
|
||||
|
||||
public void run() {
|
||||
InetSocketAddress from = null;
|
||||
public void run() {
|
||||
InetSocketAddress from = null;
|
||||
|
||||
// Run until I get killed, and all my acks have been answered
|
||||
while (running || node.hasAcks()) {
|
||||
try {
|
||||
from = (InetSocketAddress) node.getChannel().receive(buffer);
|
||||
// Run until I get killed, and all my acks have been answered
|
||||
while (running || node.hasAcks()) {
|
||||
try {
|
||||
from = (InetSocketAddress) node.getChannel().receive(buffer);
|
||||
|
||||
// channel.receive() is non-blocking. So we need to check if
|
||||
// something actually has been written to the buffer
|
||||
if (buffer.remaining() != BUF_SIZE) {
|
||||
buffer.flip();
|
||||
// channel.receive() is non-blocking. So we need to check if
|
||||
// something actually has been written to the buffer
|
||||
if (buffer.remaining() != BUF_SIZE) {
|
||||
buffer.flip();
|
||||
|
||||
byte messageType = buffer.get();
|
||||
byte messageType = buffer.get();
|
||||
|
||||
Identifier fromID = getIDFromBuffer();
|
||||
Identifier rpc_id = getIDFromBuffer();
|
||||
NodeIdentifier fromID = new NodeIdentifier(
|
||||
getIDFromBuffer().getBytes(), from);
|
||||
Identifier rpc_id = getIDFromBuffer();
|
||||
|
||||
switch (messageType) {
|
||||
case MessageType.FIND_NODE:
|
||||
receiveFindNode(from, fromID, rpc_id);
|
||||
break;
|
||||
case MessageType.NODES:
|
||||
receiveNodes(from, fromID, rpc_id);
|
||||
break;
|
||||
case MessageType.PING:
|
||||
LOGGER.log(Level.INFO, "Received [ping] from {0}",
|
||||
new Object[] { from.toString() });
|
||||
break;
|
||||
default:
|
||||
LOGGER.log(Level.INFO,
|
||||
"Received unknown command from {0}: [{1}]{2}",
|
||||
new Object[] { from.toString(), messageType,
|
||||
new String(buffer.array()) });
|
||||
}
|
||||
switch (messageType) {
|
||||
case MessageType.FIND_NODE:
|
||||
receiveFindNode(fromID, rpc_id);
|
||||
break;
|
||||
case MessageType.NODES:
|
||||
receiveNodes(fromID, rpc_id);
|
||||
break;
|
||||
case MessageType.PING:
|
||||
LOGGER.log(Level.INFO, "Received [ping] from {0}",
|
||||
new Object[] { from.toString() });
|
||||
break;
|
||||
default:
|
||||
LOGGER.log(Level.INFO,
|
||||
"Received unknown command from {0}: [{1}]{2}",
|
||||
new Object[] { from.toString(), messageType,
|
||||
new String(buffer.array()) });
|
||||
}
|
||||
|
||||
node.updateBuckets(fromID, from);
|
||||
} else {
|
||||
try {
|
||||
Thread.sleep(10);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
node.updateBuckets(new NodeIdentifier(fromID.getBytes(),
|
||||
from));
|
||||
|
||||
buffer.clear();
|
||||
} else {
|
||||
try {
|
||||
Thread.sleep(10);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
buffer.clear();
|
||||
|
||||
private void receiveNodes(InetSocketAddress from, Identifier fromID,
|
||||
Identifier rpc_id) {
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Set<BucketEntry> readEntries = new HashSet<BucketEntry>();
|
||||
private void receiveNodes(NodeIdentifier fromID, Identifier rpc_id) {
|
||||
|
||||
while (buffer.hasRemaining()) {
|
||||
InetSocketAddress address = getIPFromBuffer();
|
||||
Identifier id = getIDFromBuffer();
|
||||
BucketEntry entry = new BucketEntry(id, address);
|
||||
readEntries.add(entry);
|
||||
int numReceived = 0;
|
||||
|
||||
// TODO: Just add all nodes?!
|
||||
node.updateBuckets(id, address);
|
||||
}
|
||||
while (buffer.hasRemaining()) {
|
||||
NodeIdentifier newID = getNodeTripleFromBuffer();
|
||||
node.updateBuckets(newID);
|
||||
numReceived++;
|
||||
}
|
||||
|
||||
LOGGER.log(Level.INFO, "Received {0} [NODES] from Node {1} ({2})",
|
||||
new Object[] { readEntries.size(), fromID, from.toString() });
|
||||
}
|
||||
LOGGER.log(Level.INFO, "Received {0} [NODES] from Node {1})",
|
||||
new Object[] { numReceived, fromID });
|
||||
}
|
||||
|
||||
private void receiveFindNode(InetSocketAddress from, Identifier fromID,
|
||||
Identifier rpc_id) {
|
||||
Identifier idToFind = getIDFromBuffer();
|
||||
private void receiveFindNode(NodeIdentifier fromID, Identifier rpc_id) {
|
||||
Identifier idToFind = getIDFromBuffer();
|
||||
|
||||
LOGGER.log(Level.INFO, "Received [FIND_NODE {0}] from Node {1} ({2})",
|
||||
new Object[] { idToFind, fromID, from.toString() });
|
||||
LOGGER.log(Level.INFO, "Received [FIND_NODE {0}] from Node {1}",
|
||||
new Object[] { idToFind, fromID });
|
||||
|
||||
node.sendClosestNodesTo(from, fromID, idToFind, rpc_id);
|
||||
}
|
||||
node.sendClosestNodesTo(fromID, idToFind, rpc_id);
|
||||
}
|
||||
|
||||
public void terminate() {
|
||||
running = false;
|
||||
}
|
||||
public void terminate() {
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,94 +5,98 @@ import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import node.Identifier;
|
||||
import node.NodeIdentifier;
|
||||
|
||||
public class Bucket {
|
||||
private final static Logger LOGGER = Logger.getLogger(Bucket.class
|
||||
.getName());
|
||||
|
||||
private int size;
|
||||
private int bucketSize;
|
||||
|
||||
public List<BucketEntry> entries = new ArrayList<BucketEntry>();
|
||||
public Bucket left = null;
|
||||
public Bucket right = null;
|
||||
private List<NodeIdentifier> entries = new ArrayList<NodeIdentifier>();
|
||||
private Bucket left = null;
|
||||
private Bucket right = null;
|
||||
|
||||
private int level = 0;
|
||||
|
||||
public Bucket(int size, int level) {
|
||||
this.level = level;
|
||||
this.size = size;
|
||||
this.bucketSize = size;
|
||||
}
|
||||
|
||||
public void update(BucketEntry entry) {
|
||||
update(this, entry);
|
||||
public void update(NodeIdentifier newID) {
|
||||
update(this, newID);
|
||||
}
|
||||
|
||||
private void update(Bucket bucket, BucketEntry newEntry) {
|
||||
private void update(Bucket bucket, NodeIdentifier newID) {
|
||||
if (!bucket.isLeaf()) {
|
||||
if (newEntry.id.isBitSetAt(level)) {
|
||||
if (newID.isBitSetAt(level)) {
|
||||
|
||||
update(bucket.right, newEntry);
|
||||
update(bucket.right, newID);
|
||||
|
||||
} else {
|
||||
|
||||
update(bucket.left, newEntry);
|
||||
update(bucket.left, newID);
|
||||
|
||||
}
|
||||
} else if (bucket.isLeaf() && bucket.hasSpace()) {
|
||||
|
||||
if (entries.contains(newEntry)) {
|
||||
} else if (bucket.hasSpace()) {
|
||||
System.out.println(entries == null);
|
||||
if (entries.contains(newID)) {
|
||||
// Move to beginning
|
||||
LOGGER.log(
|
||||
Level.FINE,
|
||||
"Node {0} ({1}) already in routing table. Move to end of bucket.",
|
||||
new Object[] { newEntry.id, newEntry.address });
|
||||
if (entries.size() > 1) {
|
||||
entries.remove(newEntry);
|
||||
entries.add(newEntry);
|
||||
}
|
||||
} else {
|
||||
LOGGER.log(Level.INFO,
|
||||
"Added new node {0} ({1}) to routing table.",
|
||||
new Object[] { newEntry.id, newEntry.address });
|
||||
entries.add(newEntry);
|
||||
}
|
||||
|
||||
} else {
|
||||
// TODO: only split if necessary
|
||||
// Leaf, but full -> split
|
||||
|
||||
Bucket newLeft = new Bucket(size, level + 1);
|
||||
Bucket newRight = new Bucket(size, level + 1);
|
||||
|
||||
// Add the new entry and in the following loop distribute all
|
||||
// existing entries to left/right
|
||||
entries.add(newEntry);
|
||||
|
||||
for (BucketEntry entry : entries) {
|
||||
if (entry.id.isBitSetAt(level)) {
|
||||
newLeft.entries
|
||||
.add(new BucketEntry(entry.id, entry.address));
|
||||
} else {
|
||||
newRight.entries
|
||||
.add(new BucketEntry(entry.id, entry.address));
|
||||
"Node {0} already in routing table. Move to end of bucket.",
|
||||
new Object[] { newID });
|
||||
if (entries.size() > 1) {
|
||||
entries.remove(newID);
|
||||
entries.add(newID);
|
||||
}
|
||||
} else {
|
||||
LOGGER.log(Level.INFO, "Added new node {0} to routing table.",
|
||||
new Object[] { newID });
|
||||
entries.add(newID);
|
||||
}
|
||||
bucket.entries = null;
|
||||
bucket.left = newLeft;
|
||||
bucket.right = newRight;
|
||||
|
||||
} else { // Bucket is full
|
||||
System.out.println(entries == null);
|
||||
if (!entries.contains(newID)) {
|
||||
// TODO: only split if necessary
|
||||
|
||||
Bucket newLeft = new Bucket(bucketSize, level + 1);
|
||||
Bucket newRight = new Bucket(bucketSize, level + 1);
|
||||
|
||||
// Add the new entry and in the following loop distribute all
|
||||
// existing entries to left/right
|
||||
entries.add(newID);
|
||||
|
||||
for (NodeIdentifier entry : entries) {
|
||||
if (entry.isBitSetAt(level)) {
|
||||
newLeft.entries.add(entry);
|
||||
} else {
|
||||
newRight.entries.add(entry);
|
||||
}
|
||||
}
|
||||
bucket.entries = null;
|
||||
bucket.left = newLeft;
|
||||
bucket.right = newRight;
|
||||
} else {
|
||||
// Node is already present -> check if it's still alive
|
||||
LOGGER.log(
|
||||
Level.FINE,
|
||||
"Node {0} already in routing table. Check if still alive...",
|
||||
new Object[] { newID });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasNode(Identifier id) {
|
||||
public boolean hasNode(NodeIdentifier id) {
|
||||
return hasNode(this, id);
|
||||
}
|
||||
|
||||
private boolean hasNode(Bucket bucket, Identifier idToFind) {
|
||||
private boolean hasNode(Bucket bucket, NodeIdentifier idToFind) {
|
||||
if (bucket.isLeaf()) {
|
||||
for (BucketEntry entry : bucket.entries) {
|
||||
if (entry.id.equals(idToFind)) {
|
||||
for (NodeIdentifier id : bucket.entries) {
|
||||
if (id.equals(idToFind)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -107,18 +111,10 @@ public class Bucket {
|
||||
}
|
||||
|
||||
private boolean isLeaf() {
|
||||
return left == null && right == null;
|
||||
return left == null && right == null && entries != null;
|
||||
}
|
||||
|
||||
private boolean hasSpace() {
|
||||
return entries.size() < size;
|
||||
}
|
||||
|
||||
public List<BucketEntry> getClosestNodesTo(Identifier id) {
|
||||
List<BucketEntry> result = new ArrayList<BucketEntry>();
|
||||
|
||||
// TODO
|
||||
|
||||
return result;
|
||||
return entries.size() < bucketSize;
|
||||
}
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
package routingtable;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import util.BufferUtil;
|
||||
|
||||
import node.Identifier;
|
||||
import node.Node;
|
||||
|
||||
public class BucketEntry {
|
||||
public Identifier id;
|
||||
public InetSocketAddress address;
|
||||
|
||||
public BucketEntry(Identifier id, InetSocketAddress address) {
|
||||
this.id = id;
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof BucketEntry)) {
|
||||
return false;
|
||||
} else {
|
||||
BucketEntry entry = (BucketEntry) o;
|
||||
return id.equals(entry.id) && address.equals(entry.address);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] getBytes() {
|
||||
ByteBuffer result = ByteBuffer.allocate(8 + (Node.ID_BITS / 8));
|
||||
result.put(BufferUtil.addrToBytes(address));
|
||||
result.put(id.getBytes());
|
||||
return result.array();
|
||||
}
|
||||
}
|
||||
@ -1,43 +1,67 @@
|
||||
package routingtable;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import node.Identifier;
|
||||
import node.Node;
|
||||
import node.NodeIdentifier;
|
||||
|
||||
public class RoutingTable {
|
||||
|
||||
private Bucket tree;
|
||||
private Bucket tree;
|
||||
|
||||
private Set<BucketEntry> entries = new HashSet<BucketEntry>();
|
||||
private Set<NodeIdentifier> entries = new HashSet<NodeIdentifier>();
|
||||
|
||||
private int bucketSize;
|
||||
private int bucketSize;
|
||||
|
||||
public RoutingTable(int bucketSize) {
|
||||
this.tree = new Bucket(bucketSize, 0);
|
||||
this.bucketSize = bucketSize;
|
||||
}
|
||||
public RoutingTable(int bucketSize) {
|
||||
this.tree = new Bucket(bucketSize, 0);
|
||||
this.bucketSize = bucketSize;
|
||||
}
|
||||
|
||||
public void update(Identifier id, InetSocketAddress address) {
|
||||
BucketEntry newEntry = new BucketEntry(id, address);
|
||||
entries.add(newEntry);
|
||||
tree.update(newEntry);
|
||||
}
|
||||
public void update(NodeIdentifier id) {
|
||||
entries.add(id);
|
||||
tree.update(id);
|
||||
}
|
||||
|
||||
public Set<BucketEntry> getClosestNodesTo(Identifier id) {
|
||||
Set<BucketEntry> result = new HashSet<BucketEntry>();
|
||||
public Set<NodeIdentifier> getClosestNodesTo(final Identifier id) {
|
||||
Set<NodeIdentifier> result = new HashSet<NodeIdentifier>();
|
||||
|
||||
if (entries.size() <= bucketSize) {
|
||||
result.addAll(entries);
|
||||
return result;
|
||||
} else {
|
||||
// TODO get all nodes that are closest..
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (entries.size() <= bucketSize) {
|
||||
result.addAll(entries);
|
||||
|
||||
public void remove(Identifier node) {
|
||||
} else {
|
||||
List<NodeIdentifier> temp = new ArrayList<NodeIdentifier>(entries);
|
||||
|
||||
}
|
||||
Collections.sort(temp, new Comparator<NodeIdentifier>() {
|
||||
@Override
|
||||
public int compare(NodeIdentifier o1, NodeIdentifier o2) {
|
||||
BigInteger dist1 = id.distanceTo(o1);
|
||||
BigInteger dist2 = id.distanceTo(o2);
|
||||
return dist1.compareTo(dist2);
|
||||
}
|
||||
});
|
||||
|
||||
for (int i = 0; i < Node.BUCKET_SIZE; i++) {
|
||||
result.add(temp.get(i));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void remove(Identifier node) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
public Set<NodeIdentifier> getEntries() {
|
||||
return entries;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user