diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..d16a49b --- /dev/null +++ b/.classpath @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/.project b/.project new file mode 100644 index 0000000..2393939 --- /dev/null +++ b/.project @@ -0,0 +1,17 @@ + + + reload + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/reload/Common/AddressType.java b/reload/Common/AddressType.java new file mode 100644 index 0000000..7dd1598 --- /dev/null +++ b/reload/Common/AddressType.java @@ -0,0 +1,48 @@ + + package reload.Common; + + /* Constructor: + AddressType type = AddressType.valueOf(1); + AddressType type = AddressType.ipv4_address; + */ + + public enum AddressType { + UNDEFINED( "undefined", (byte)-1), + reservedAddr("reserved address", (byte)0), + ipv4_address("ipv4 address", (byte)1), + ipv6_address("ipv6 address", (byte)2); + + + final String name; + final byte value; + + private AddressType(String name, byte value) { + this.name = name; + this.value = value; + } + + + public static AddressType valueOf(int value) { + AddressType type = UNDEFINED; + switch (value) { + case 0: + type = reservedAddr; + break; + case 1: + type = ipv4_address; + break; + case 2: + type = ipv6_address; + break; + } + + return type; + } + + public byte getBytes(){ + + return value; + + } + + } \ No newline at end of file diff --git a/reload/Common/Algorithm.java b/reload/Common/Algorithm.java new file mode 100644 index 0000000..8eabd92 --- /dev/null +++ b/reload/Common/Algorithm.java @@ -0,0 +1,89 @@ + package reload.Common; + + import reload.Forwarding.Request.CandType; + import reload.Common.Exception.*; + + public class Algorithm{ + + public static int counter(int size, byte[] data, int sumPosition) throws ReloadException{ + + + if(data.length==0) + return 0; + + if(size != 1 && size !=2 && size !=4 && size !=8 && size !=16 && size !=32) + throw new ReloadException("Incorrect size. Only 1, 2 and 4 bytes are allowed. Only 8, 16 and 32 bits are allowed."); + + if(size>7) + size=size/8; + + + int count=0; + int position = sumPosition; + + for(boolean salir=false; !salir; count++){ + + if(size==4) + position += Utils.toInt(data, position)+size; + + if(size==2) + position += Utils.toShort(data, position)+size; + + if(size==1) + position += data[position]+size; + + if(position == data.length) + salir=true; + + position += sumPosition; + + } + + return count; + + } + + + public static int AttachCounter(byte[] data){ + + + if(data.length==0) + return 0; + + int position=0; + + + int count=0; + + for(boolean salir=false; !salir; count++){ + + position += data[position+1]+2; // IPAddresssPort + + position++; //OverleyLinkType + + position += data[position]+1; // Opaque foundation + + position += 4; // int priority + + CandType type = CandType.valueOf(data[position]); + + position++; // CandType + + if (type == CandType.relay) + position += data[position+1]+2; // IPAddresssPort + + short ext_length = Utils.toShort(data, position); //short + position += 2; + + + position += ext_length; // IceExtension[] + + if(position == data.length) + salir=true; + + } + + return count; + + } + } \ No newline at end of file diff --git a/reload/Common/DataModel.java b/reload/Common/DataModel.java new file mode 100644 index 0000000..60d9681 --- /dev/null +++ b/reload/Common/DataModel.java @@ -0,0 +1,47 @@ + package reload.Common; + + /* Constructor: + DataModel type = DataModel.valueOf(1); + DataModel type = DataModel.single_value; + */ + + public enum DataModel { + UNDEFINED( "undefined", (byte)-1), + single_value("single value", (byte)1), + array( "array", (byte)2), + dictionary( "dictionary", (byte)3); + + + final String name; + final byte value; + + private DataModel(String name, byte value) { + this.name = name; + this.value = value; + } + + + public static DataModel valueOf(int value) { + DataModel type = UNDEFINED; + switch (value) { + case 1: + type = single_value; + break; + case 2: + type = array; + break; + case 3: + type = dictionary; + break; + } + + return type; + } + + public byte getBytes(){ + + return value; + + } + + } \ No newline at end of file diff --git a/reload/Common/DataStructure.java b/reload/Common/DataStructure.java new file mode 100644 index 0000000..de472ce --- /dev/null +++ b/reload/Common/DataStructure.java @@ -0,0 +1,106 @@ + + package reload.Common; + + import reload.Storage.Data.DictionaryKey; + + public class DataStructure{ + + private DictionaryKey key; // For Dictionary only + private long storage_time; + private int life_time; + private boolean exists; + private Opaque value; + + private boolean dictionary; + + + public DataStructure(DictionaryKey key, long storage_time, int life_time, boolean exists, Opaque value){ + + this.key = key; + this.storage_time = storage_time; + this.life_time = life_time; + this.exists = exists; + this.value = value; + + dictionary = true; + + } + + public DataStructure(long storage_time, int life_time, boolean exists, Opaque value){ + + this.storage_time = storage_time; + this.life_time = life_time; + this.exists = exists; + this.value = value; + + dictionary = false; + + } + + public DataStructure(){ // Empty, exists=false + + } + + public DictionaryKey getDictionaryKey(){ + + return key; + + } + + public long getStorageTime(){ + + return storage_time; + + } + + public int getLifeTime(){ + + + return life_time; + + } + + public boolean getExists(){ + + + return exists; + + } + + public Opaque getValue(){ + + return value; + + } + + public boolean isDictionary(){ + + return dictionary; + + } + + public String print(){ + + String ret = new String(); + + if(dictionary){ + byte[] id = key.getKey(); + ret +="0x"; + for(int k=0; k 0xffff) + throw new WrongTypeReloadException("Input value must be a 16-bit positive short number."); + + if(value >= 0x8000 && value <= 0xfffe) + return reserved; + + ErrorCode code; + + switch (value) { + case 0: + code = invalid; + break; + case 1: + code = unused; + break; + case 2: + code = error_forbidden; + break; + case 3: + code = error_not_found; + break; + case 4: + code = error_request_timeout; + break; + case 5: + code = error_generation_counter_too_low; + break; + case 6: + code = error_incompatible_with_overlay; + break; + case 7: + code = error_unsupported_forwarding_option; + break; + case 8: + code = error_data_too_large; + break; + case 9: + code = error_data_too_old; + break; + case 10: + code = error_ttl_exceeded; + break; + case 11: + code = error_message_too_large; + break; + case 12: + code = error_unknown_kind; + break; + case 13: + code = error_unknown_extension; + break; + case 14: + code = error_response_too_large; + break; + case 15: + code = error_config_too_old; + break; + case 16: + code = error_config_too_new; + break; + case 17: + code = error_in_progress; + break; + case 18: + code = error_exp_a; + break; + case 19: + code = error_exp_b; + break; + case 20: + code = error_invalid_message; + break; + default: + code = unused; + } + + return code; + } + + public short getValue(){ + + return value; + + } + + } \ No newline at end of file diff --git a/reload/Common/Exception/NotTrueNorFalseReloadException.java b/reload/Common/Exception/NotTrueNorFalseReloadException.java new file mode 100644 index 0000000..02e033f --- /dev/null +++ b/reload/Common/Exception/NotTrueNorFalseReloadException.java @@ -0,0 +1,12 @@ + package reload.Common.Exception; + + public class NotTrueNorFalseReloadException extends ReloadException { + + public NotTrueNorFalseReloadException() { + + super("Wrong Boolean value."); + + } + + + } \ No newline at end of file diff --git a/reload/Common/Exception/ReloadException.java b/reload/Common/Exception/ReloadException.java new file mode 100644 index 0000000..051dd1f --- /dev/null +++ b/reload/Common/Exception/ReloadException.java @@ -0,0 +1,11 @@ + package reload.Common.Exception; + + public class ReloadException extends Exception { + + public ReloadException(String message) { + + super(message); + + } + + } \ No newline at end of file diff --git a/reload/Common/Exception/UnimplementedReloadException.java b/reload/Common/Exception/UnimplementedReloadException.java new file mode 100644 index 0000000..632609b --- /dev/null +++ b/reload/Common/Exception/UnimplementedReloadException.java @@ -0,0 +1,13 @@ + package reload.Common.Exception; + + public class UnimplementedReloadException extends ReloadException { + + + public UnimplementedReloadException(String feature) { + + super(feature + " not implemented in this version."); + + } + + + } \ No newline at end of file diff --git a/reload/Common/Exception/WrongLengthReloadException.java b/reload/Common/Exception/WrongLengthReloadException.java new file mode 100644 index 0000000..ca9f10e --- /dev/null +++ b/reload/Common/Exception/WrongLengthReloadException.java @@ -0,0 +1,18 @@ + package reload.Common.Exception; + + public class WrongLengthReloadException extends ReloadException { + + + public WrongLengthReloadException() { + + super("Data length is bigger/smaller than allowed."); + + } + + public WrongLengthReloadException(String msg) { + + super(msg); + + } + + } \ No newline at end of file diff --git a/reload/Common/Exception/WrongPacketReloadException.java b/reload/Common/Exception/WrongPacketReloadException.java new file mode 100644 index 0000000..c0f7d49 --- /dev/null +++ b/reload/Common/Exception/WrongPacketReloadException.java @@ -0,0 +1,23 @@ + package reload.Common.Exception; + + import reload.Common.MessageCode; + + public class WrongPacketReloadException extends ReloadException { + + + public WrongPacketReloadException(int code) throws ReloadException{ + + super(MessageCode.valueOf(code).getName() + " was espected to be received."); + + // Extender con un type que devuelva un string para que quede bonito. + + } + + /*public WrongTypeReloadException() { + + super("No type has been selected."); + + }*/ + + + } \ No newline at end of file diff --git a/reload/Common/Exception/WrongTypeReloadException.java b/reload/Common/Exception/WrongTypeReloadException.java new file mode 100644 index 0000000..6e7db82 --- /dev/null +++ b/reload/Common/Exception/WrongTypeReloadException.java @@ -0,0 +1,19 @@ + package reload.Common.Exception; + + public class WrongTypeReloadException extends ReloadException { + + + public WrongTypeReloadException(String message) { + + super(message); + + } + + public WrongTypeReloadException() { + + super("No type has been selected."); + + } + + + } \ No newline at end of file diff --git a/reload/Common/IPv4AddrPort.java b/reload/Common/IPv4AddrPort.java new file mode 100644 index 0000000..6d134f3 --- /dev/null +++ b/reload/Common/IPv4AddrPort.java @@ -0,0 +1,90 @@ + package reload.Common; + import java.io.*; + import java.net.*; + import reload.*; + + public class IPv4AddrPort{ + + private int addr; + private short port; + + + + public IPv4AddrPort (int addr, short port){ + + this.addr = addr; + this.port = port; + + } + + public IPv4AddrPort (int b0, int b1, int b2, int b3, int port){ + + byte b[] = new byte[4]; + b[0] = (byte)b0; + b[1] = (byte)b1; + b[2] = (byte)b2; + b[3] = (byte)b3; + + this.addr = Utils.toInt(b, 0); + this.port = (short)port; + + } + + public IPv4AddrPort (String addr, int port) throws UnknownHostException{ + + this((Inet4Address)InetAddress.getByName(addr), port); + + } + + public IPv4AddrPort (InetAddress addr, int port) throws UnknownHostException{ + + this((Inet4Address)addr, port); + + } + + public IPv4AddrPort (Inet4Address addr, int port){ + + this.addr = Utils.toInt(addr.getAddress(), 0); + this.port = (short)port; + + } + + public IPv4AddrPort (byte[] data){ + + addr = Utils.toInt(data, 0); + port = Utils.toShort(data, 4); + + } + + public IPv4AddrPort (byte[] data, int port){ + + addr = Utils.toInt(data, 0); + port = (short)port; + + } + + public byte[] getBytes() throws IOException{ + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + baos.write(Utils.toByte(addr)); + baos.write(Utils.toByte(port)); + + return baos.toByteArray(); + + } + + public byte[] getAddressBytes() throws IOException{ + + return Utils.toByte(addr); + + } + + public byte[] getPortBytes() throws IOException{ + + return Utils.toByte(port); + + } + + + } \ No newline at end of file diff --git a/reload/Common/IPv6AddrPort.java b/reload/Common/IPv6AddrPort.java new file mode 100644 index 0000000..f580b9f --- /dev/null +++ b/reload/Common/IPv6AddrPort.java @@ -0,0 +1,78 @@ +package reload.Common; +import java.io.*; +import java.net.*; +import java.util.UUID; +import reload.*; + +public class IPv6AddrPort{ + + private UUID addr; //128-bit integer + private short port; + + + + public IPv6AddrPort (UUID addr, short port){ + + this.addr = addr; + this.port = port; + + } + + public IPv6AddrPort (Inet6Address addr, int port){ + + this(Utils.toUUID(addr.getAddress(), 0), (short)port); + + } + + public IPv6AddrPort (InetAddress addr, int port) throws UnknownHostException{ + + this((Inet6Address)addr, port); + + } + + public IPv6AddrPort (String address, int port) throws UnknownHostException{ + + this((Inet6Address)InetAddress.getByName(address), port); + + } + + public IPv6AddrPort (byte[] data){ + + addr = Utils.toUUID(data, 0); + port = Utils.toShort(data, 16); + + } + + public IPv6AddrPort (byte[] data, int port){ + + addr = Utils.toUUID(data, 0); + port = (short)port; + + } + + public byte[] getBytes() throws IOException{ + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + baos.write(Utils.toByte(addr.getMostSignificantBits())); + baos.write(Utils.toByte(addr.getLeastSignificantBits())); + baos.write(Utils.toByte(port)); + + return baos.toByteArray(); + + } + + public byte[] getAddressBytes() throws IOException{ + + return Utils.toByte(addr); + + } + + public byte[] getPortBytes() throws IOException{ + + return Utils.toByte(port); + + } + + +} \ No newline at end of file diff --git a/reload/Common/Id.java b/reload/Common/Id.java new file mode 100644 index 0000000..f392804 --- /dev/null +++ b/reload/Common/Id.java @@ -0,0 +1,217 @@ + package reload.Common; + + import reload.Message.Forwarding.DestinationType; + import java.math.BigInteger; + import reload.Common.Exception.*; + + public class Id{ + + protected byte[] id; + + protected DestinationType type; + + public final static byte[] ones = {(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF}; + + + public Id(){ + + type = DestinationType.UNDEFINED; + + } + + public boolean equals(Id node) throws NotTrueNorFalseReloadException{ + + if(node==null) + throw new NotTrueNorFalseReloadException(); + + byte[] idn = node.getId(); + + if(id.length != idn.length) + return false; + + for (int i=0; i 128) + throw new WrongLengthReloadException(); + + BigInteger b = new BigInteger(1, id); + + BigInteger sum = b.add(num); + + if(type != DestinationType.node && type != DestinationType.resource) + throw new WrongTypeReloadException(); + + if(sum.compareTo(new BigInteger(1,ones)) == 1){ + + BigInteger bi = sum.subtract(new BigInteger(1,ones)).subtract(BigInteger.ONE); + id = toByteArray(bi); + + } + else + id = toByteArray(sum); + + } + + public void add(int num) throws Exception{ + + add(BigInteger.valueOf(num)); + + } + + /* Returns shorter distance in a positive or negative value. Module is the distance (same as distanceAbs), positive signum means for clockwise and negative means against clockwise. */ + public BigInteger distance(Id node){ + + boolean signum = false; // Positive + + BigInteger num1 = new BigInteger(1, id); + BigInteger num2 = new BigInteger(1, node.getId()); + + if (num1.compareTo(num2) == 1) + signum = true; // Negative + + BigInteger a = num1.subtract(num2).abs(); + BigInteger b = a.subtract(new BigInteger(1,ones)).abs().add(BigInteger.ONE); + + if (a.compareTo(b) == 1) + signum = !signum; // Switch + + BigInteger res = a.min(b); + + if(signum) // Negative + res = res.negate(); + + return res; + + } + + /* Returs shorter distance in absolute value. */ + public BigInteger distanceAbs(Id node){ + + return distance(node).abs(); + + } + + /* Returs distance always for clockwise, although is not the shorter one. */ + public BigInteger distancePos(Id node){ + + BigInteger num1 = new BigInteger(1, id); + BigInteger num2 = new BigInteger(1, node.getId()); + + BigInteger res = num2.subtract(num1); + if(res.signum() == -1) + res = res.add(new BigInteger(1,ones)).add(BigInteger.ONE); + //res = res.add(BigInteger.valueOf(100)); + + return res; + + } + + public String print(){ + + String ret = new String("0x"); + + for(int i=0; i=0; i--) + result[i] = temp[i+1]; + } + + else{ + + for (int i=15, j=temp.length-1; j>=0; i--, j--) + result[i] = temp[j]; + } + + return result; + + } + + } \ No newline at end of file diff --git a/reload/Common/IpAddressPort.java b/reload/Common/IpAddressPort.java new file mode 100644 index 0000000..9561295 --- /dev/null +++ b/reload/Common/IpAddressPort.java @@ -0,0 +1,214 @@ + package reload.Common; + import java.io.*; + import java.net.*; + import reload.*; + import reload.Common.Exception.*; + + public class IpAddressPort{ + + + private AddressType type; + private byte length; + + private IPv4AddrPort v4addr_port; + private IPv6AddrPort v6addr_port; + + + + public IpAddressPort (IPv4AddrPort v4addr_port) throws IOException{ + + type = AddressType.ipv4_address; + length = (byte)v4addr_port.getBytes().length; + this.v4addr_port = v4addr_port; + + } + + public IpAddressPort (IPv6AddrPort v6addr_port) throws IOException{ + + type = AddressType.ipv6_address; + length = (byte)v6addr_port.getBytes().length; + this.v6addr_port = v6addr_port; + + } + + public IpAddressPort (String addr, int port) throws Exception{ + + InetAddress ia = InetAddress.getByName(addr); + + if(ia instanceof Inet4Address) + type = AddressType.ipv4_address; + if(ia instanceof Inet6Address) + type = AddressType.ipv6_address; + + + if(type == AddressType.ipv4_address){ + v4addr_port = new IPv4AddrPort(addr, port); + length = (byte)v4addr_port.getBytes().length; + } + + else if(type == AddressType.ipv6_address){ + v6addr_port = new IPv6AddrPort(addr, port); + length = (byte)v6addr_port.getBytes().length; + } + + else + throw new WrongTypeReloadException(); + + } + + public IpAddressPort (InetAddress addr, int port) throws Exception{ + + if(addr instanceof Inet4Address) + type = AddressType.ipv4_address; + if(addr instanceof Inet6Address) + type = AddressType.ipv6_address; + + + if(type == AddressType.ipv4_address){ + v4addr_port = new IPv4AddrPort(addr, port); + length = (byte)v4addr_port.getBytes().length; + } + + else if(type == AddressType.ipv6_address){ + v6addr_port = new IPv6AddrPort(addr, port); + length = (byte)v6addr_port.getBytes().length; + } + + else + throw new WrongTypeReloadException(); + + } + + public IpAddressPort (byte[] data) throws IOException{ + + type = AddressType.valueOf(data[0]); + length = data[1]; + + switch(type.getBytes()){ + + case 1: + + v4addr_port = new IPv4AddrPort(Utils.cutArray(data, 2)); + break; + + case 2: + + v6addr_port = new IPv6AddrPort(Utils.cutArray(data, 2)); + } + + } + + public IpAddressPort (byte[] address, int port) throws Exception{ + + if(address.length == 4) + type = AddressType.ipv4_address; + else if(address.length == 16) + type = AddressType.ipv6_address; + else + throw new WrongTypeReloadException(); + + + if(type == AddressType.ipv4_address){ + v4addr_port = new IPv4AddrPort(address, port); + length = (byte)v4addr_port.getBytes().length; + } + + else if(type == AddressType.ipv6_address){ + v6addr_port = new IPv6AddrPort(address, port); + length = (byte)v6addr_port.getBytes().length; + } + + else + throw new WrongTypeReloadException(); + + } + + public byte[] getBytes() throws IOException{ + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + baos.write(type.getBytes()); + baos.write(length); + + switch(type.getBytes()){ + + case 1: + + baos.write(v4addr_port.getBytes()); + break; + + case 2: + + baos.write(v6addr_port.getBytes()); + + } + + return baos.toByteArray(); + + } + + public byte getLength(){ + + return length; + } + + public InetAddress getAddress() throws Exception{ + + if(type == AddressType.ipv4_address) + return (Inet4Address)InetAddress.getByAddress(Utils.cutArray(v4addr_port.getBytes(), 4, 0)); + + else if(type == AddressType.ipv6_address) + return (Inet6Address)InetAddress.getByAddress(Utils.cutArray(v6addr_port.getBytes(), 16, 0)); + + else + throw new WrongTypeReloadException(); + + } + + public short getPort() throws Exception{ + + if(type == AddressType.ipv4_address) + return Utils.toShort(v4addr_port.getBytes(), 4); + + else if(type == AddressType.ipv6_address) + return Utils.toShort(v6addr_port.getBytes(), 16); + + else + throw new WrongTypeReloadException(); + + + } + + public byte[] getAddressBytes() throws Exception{ + + if(type == AddressType.ipv4_address) + return v4addr_port.getAddressBytes(); + + else if(type == AddressType.ipv6_address) + return v6addr_port.getAddressBytes(); + + else + throw new WrongTypeReloadException(); + + } + + public byte[] getPortBytes() throws Exception{ + + if(type == AddressType.ipv4_address) + return v4addr_port.getPortBytes(); + + else if(type == AddressType.ipv6_address) + return v6addr_port.getPortBytes(); + + else + throw new WrongTypeReloadException(); + + } + + public AddressType getType(){ + + return type; + + } + + } \ No newline at end of file diff --git a/reload/Common/KindArray.java b/reload/Common/KindArray.java new file mode 100644 index 0000000..9d80253 --- /dev/null +++ b/reload/Common/KindArray.java @@ -0,0 +1,58 @@ + package reload.Common; + + import java.io.*; + import reload.Common.Exception.*; + + public class KindArray{ + + private byte kind_length; + private KindId[] kind_array; //<0..2^8-1> + + + public KindArray (KindId[] kind_array) throws Exception{ + + this.kind_array = kind_array; + + for (int i=0; i Math.pow(2, 8)-1) + throw new WrongLengthReloadException(); + + } + + public KindArray (byte[] data) throws Exception{ + + kind_length = data[0]; + + data = Utils.cutArray(data, kind_length, 1); + + int offset = 0; + + int num = data.length / 4; //32-bit, 4 bytes + + kind_array = new KindId[num]; + + for (int i=0; i 0xffff) + throw new WrongTypeReloadException("Input value must be a 16-bit positive short number."); + + if(value >= 0x8000 && value <= 0xfffe) + return reserved; + + MessageCode code; + + switch (value) { + case 0: + code = invalid; + break; + case 1: + code = probe_req; + break; + case 2: + code = probe_ans; + break; + case 3: + code = attach_req; + break; + case 4: + code = attach_ans; + break; + case 7: + code = store_req; + break; + case 8: + code = store_ans; + break; + case 9: + code = fetch_req; + break; + case 10: + code = fetch_ans; + break; + case 13: + code = find_req; + break; + case 14: + code = find_ans; + break; + case 15: + code = join_req; + break; + case 16: + code = join_ans; + break; + case 17: + code = leave_req; + break; + case 18: + code = leave_ans; + break; + case 19: + code = update_req; + break; + case 20: + code = update_ans; + break; + case 21: + code = route_query_req; + break; + case 22: + code = route_query_ans; + break; + case 23: + code = ping_req; + break; + case 24: + code = ping_ans; + break; + case 25: + code = stat_req; + break; + case 26: + code = stat_ans; + break; + case 29: + code = app_attach_req; + break; + case 30: + code = app_attach_ans; + break; + case 33: + code = config_update_req; + break; + case 34: + code = config_update_ans; + break; + case 35: + code = exp_a_req; + break; + case 36: + code = exp_a_ans; + break; + case 37: + code = exp_b_req; + break; + case 38: + code = exp_b_ans; + break; + case 0xffff: + code = error; + break; + default: + code = unused; + } + + return code; + } + + public short getValue(){ + + return value; + + } + + public String getName(){ + + return name; + + } + + } \ No newline at end of file diff --git a/reload/Common/Module.java b/reload/Common/Module.java new file mode 100644 index 0000000..cf10302 --- /dev/null +++ b/reload/Common/Module.java @@ -0,0 +1,14 @@ + package reload.Common; + + + public class Module{ + + public static reload.Message.MessageTransport msg; + + public static reload.Storage.StorageInterface si; + + public static reload.Topology.TopologyPluginInterface tpi; + + public static reload.Forwarding.ForwardingAndLinkInterface falm; + + } \ No newline at end of file diff --git a/reload/Common/Nat.java b/reload/Common/Nat.java new file mode 100644 index 0000000..a34c0b3 --- /dev/null +++ b/reload/Common/Nat.java @@ -0,0 +1,52 @@ + package reload.Common; + + import java.io.*; + import java.net.*; + + + public class Nat{ + + public static InetAddress myIP; + public static String uri; + + public static void setMyIp(IpAddressPort IP) throws Exception{ + + InetAddress remote = IP.getAddress(); + InetAddress internal = InetAddress.getLocalHost(); + + if(internal.isSiteLocalAddress() && !remote.isSiteLocalAddress() && IP.getType() == AddressType.ipv4_address) + myIP = (Inet4Address)InetAddress.getByName(getIp()); + + else + myIP = internal; + + } + + public static void setMyIp(boolean external) throws Exception{ + + if(external) + myIP = (Inet4Address)InetAddress.getByName(getIp()); + + else + myIP = InetAddress.getLocalHost(); + + } + + public static String getIp() throws Exception { + + + URL whatismyip = new URL("http://checkip.amazonaws.com"); + BufferedReader in = null; + try { + in = new BufferedReader(new InputStreamReader(whatismyip.openStream())); + String ip = in.readLine(); + return ip; + } + finally { + if (in != null) + in.close(); + } + + } + + } diff --git a/reload/Common/NodeId.java b/reload/Common/NodeId.java new file mode 100644 index 0000000..ab3de25 --- /dev/null +++ b/reload/Common/NodeId.java @@ -0,0 +1,154 @@ + package reload.Common; + + import java.util.UUID; + import java.io.*; + import java.math.BigInteger; + import reload.Message.Forwarding.DestinationType; + import reload.Common.Exception.*; + + public class NodeId extends Id{ + + + private int length; + + + public NodeId(byte[] data, boolean upper) throws Exception{ //128 to 160 bit + + XML configuration = new XML(); + length = configuration.getNodeIDLength(); + + if(length < 16 || length > 20) + throw new WrongLengthReloadException(); + + if(upper){ + + if(data.length != length) + throw new WrongLengthReloadException(); + + id = data; + + } + + else + id = Utils.cutArray(data, length, 0); + + type = DestinationType.node; // Extended + + } + + public NodeId(BigInteger data) throws Exception{ //128 to 160 bit, positive BigInteger ONLY + + + if(data.signum()==-1) + throw new NumberFormatException("Negative BigInteger not allowed."); + + + XML configuration = new XML(); + length = configuration.getNodeIDLength(); + + if(length < 16 || length > 20) + throw new WrongLengthReloadException(); + + if((float)(data.bitLength())/8 > length) + throw new WrongLengthReloadException(); + + + id = new byte[length]; //16 + byte[] temp = data.toByteArray(); + + + if(temp.length == length+1){ //17 + + if (temp[0] != 0) + throw new NumberFormatException("Fatal Error."); // Should not occur. + + for (int i=length-1; i>=0; i--) //15 + id[i] = temp[i+1]; + } + + else{ + + for (int i=length-1, j=temp.length-1; j>=0; i--, j--) //15 + id[i] = temp[j]; + } + + type = DestinationType.node; // Extended + + } + + public NodeId(int data) throws Exception{ // For testing + + this(BigInteger.valueOf(data)); + + } + + public NodeId() throws Exception{ //Empty Node-ID + + this(new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, true); + + } + + public NodeId(UUID data) throws Exception{ // Supposing 128 bits and upper call + + XML configuration = new XML(); + length = configuration.getNodeIDLength(); + + if(length != 16) + throw new WrongLengthReloadException(); + + id = Utils.toByte(data); + + type = DestinationType.node; // Extended + + } + + public NodeId sum(int num) throws Exception{ + + NodeId node = new NodeId(id, true); + node.add(num); + return node; + + } + + public boolean isEmpty(){ + + if(Utils.equals(id, new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0})) + return true; + + else + return false; + + } + + public boolean isWildcard(){ // Wildcard node-ID + + if(Utils.equals(id, ones)) + return true; + + else + return false; + + } + + public void setOnes(){ + + id = ones; + + } + + public static int getLength() throws Exception{ + + XML configuration = new XML(); + int length = configuration.getNodeIDLength(); + + return length; + + } + + public byte[] getBytes(){ + + return id; + + } + + } \ No newline at end of file diff --git a/reload/Common/Opaque.java b/reload/Common/Opaque.java new file mode 100644 index 0000000..a553b2e --- /dev/null +++ b/reload/Common/Opaque.java @@ -0,0 +1,113 @@ + package reload.Common; + + import java.io.*; + import reload.Common.Exception.*; + + public class Opaque{ + + + private byte length; + private short lengthS; + private int lengthI; + + private int bits; + + private byte[] cont; + + + public Opaque(int bits, byte[] data) throws ReloadException{ // Upper + + if(bits != 8 && bits != 16 && bits != 24 && bits != 32) + throw new ReloadException("Incorrect bits length. Only 8, 16, 24 and 32 are allowed."); + + if(data.length > Math.pow(2, bits)-1) + throw new WrongLengthReloadException(); + + this.bits = bits; + cont = data; + + switch(bits){ + case 8: + length = (byte)data.length; + break; + case 16: + lengthS = (short)data.length; + break; + case 32: + lengthI = data.length; + break; + case 24: + lengthI = data.length; + } + + } + + public Opaque(int bits, byte[] data, int offset) throws ReloadException{ // Lower + + if(bits != 8 && bits != 16 && bits != 24 && bits != 32) + throw new ReloadException("Incorrect bits length. Only 8, 16, 24 and 32 are allowed."); + + + this.bits = bits; + + + switch(bits){ + case 8: + length = data[offset]; + cont = Utils.cutArray(data, length, offset+1); + break; + case 16: + lengthS = Utils.toShort(data, offset); + cont = Utils.cutArray(data, lengthS, offset+2); + break; + case 32: + lengthI = Utils.toInt(data, offset); + cont = Utils.cutArray(data, lengthI, offset+4); + break; + case 24: + lengthI = Utils.to3Bytes(data, offset); + cont = Utils.cutArray(data, lengthI, offset+3); + } + + if(cont.length > Math.pow(2, bits)-1) + throw new WrongLengthReloadException(); + + } + + public byte[] getBytes() throws IOException{ + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + switch(bits){ + case 8: + baos.write(length); + break; + case 16: + baos.write(Utils.toByte(lengthS)); + break; + case 32: + baos.write(Utils.toByte(lengthI)); + break; + case 24: + baos.write(Utils.to3Bytes(lengthI)); + } + + baos.write(cont); + + return baos.toByteArray(); + + } + + public byte[] getContent(){ + + return cont; + + } + + public int getBits(){ + + return bits; + + } + + } \ No newline at end of file diff --git a/reload/Common/ResourceId.java b/reload/Common/ResourceId.java new file mode 100644 index 0000000..6307548 --- /dev/null +++ b/reload/Common/ResourceId.java @@ -0,0 +1,85 @@ + package reload.Common; + + import java.util.Random; + import java.math.BigInteger; + import java.io.ByteArrayOutputStream; + import reload.Message.Forwarding.DestinationType; + import reload.Common.Exception.*; + + // Should be variable-length but it is a 128-bit number + + public class ResourceId extends Id{ + + private static byte length = 16; // For Chord + + //public final static byte[] ones = {(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF}; + + + public ResourceId(byte[] data, boolean upper) throws WrongLengthReloadException{ + + if(upper){ + + if(data.length != 16) // Chord + throw new WrongLengthReloadException(); + + id = data; + + } + + else{ + + id = Utils.cutArray(data, data[0], 1); + length = data[0]; + + if(length != 16) // Chord + throw new WrongLengthReloadException(); + + } + + type = DestinationType.resource; // Extended + + } + + public ResourceId (BigInteger id) throws Exception{ + + if(id.signum()==-1) + throw new NumberFormatException("Negative BigInteger not allowed."); + + if (id.bitLength() > 128) + throw new WrongLengthReloadException(); + + this.id = toByteArray(id); + + type = DestinationType.resource; // Extended + + } + + public ResourceId (long id) throws Exception{ + + this(BigInteger.valueOf(id)); + + } + + public ResourceId() { // Random + + id = toByteArray(new BigInteger(128, new Random())); + + type = DestinationType.resource; // Extended + + } + + // Not equal to getId(), getBytes() returns length and id, while getId() returns id only + public byte[] getBytes() throws java.io.IOException{ + + //return id; + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + baos.write(length); + baos.write(id); + + return baos.toByteArray(); + + } + + } \ No newline at end of file diff --git a/reload/Common/Utils.java b/reload/Common/Utils.java new file mode 100644 index 0000000..d503d7b --- /dev/null +++ b/reload/Common/Utils.java @@ -0,0 +1,190 @@ + package reload.Common; + + import java.util.UUID; + import java.math.BigInteger; + import reload.Storage.Data.ArrayRange; + import reload.Common.Exception.*; + + public class Utils{ + + public static byte[] toByte(int value) { + return new byte[] { + (byte)(value >>> 24), + (byte)(value >>> 16), + (byte)(value >>> 8), + (byte)value}; + } + + public static byte[] to3Bytes(int value) { + return new byte[] { + (byte)(value >>> 16), + (byte)(value >>> 8), + (byte)value}; + } + + public static byte[] toByte(short value) { + return new byte[] { + (byte)(value >>> 8), + (byte)value}; + } + + public static byte[] toByte(long value) { + return new byte[] { + (byte)(value >>> 56), + (byte)(value >>> 48), + (byte)(value >>> 40), + (byte)(value >>> 32), + (byte)(value >>> 24), + (byte)(value >>> 16), + (byte)(value >>> 8), + (byte)value}; + } + + public static byte[] toByte(UUID value) { + return new byte[] { + (byte)(value.getMostSignificantBits() >>> 56), + (byte)(value.getMostSignificantBits() >>> 48), + (byte)(value.getMostSignificantBits() >>> 40), + (byte)(value.getMostSignificantBits() >>> 32), + (byte)(value.getMostSignificantBits() >>> 24), + (byte)(value.getMostSignificantBits() >>> 16), + (byte)(value.getMostSignificantBits() >>> 8), + (byte) value.getMostSignificantBits(), + (byte)(value.getLeastSignificantBits() >>> 56), + (byte)(value.getLeastSignificantBits() >>> 48), + (byte)(value.getLeastSignificantBits() >>> 40), + (byte)(value.getLeastSignificantBits() >>> 32), + (byte)(value.getLeastSignificantBits() >>> 24), + (byte)(value.getLeastSignificantBits() >>> 16), + (byte)(value.getLeastSignificantBits() >>> 8), + (byte) value.getLeastSignificantBits() }; + } + + public static byte toByte(boolean value) { + + if(value) + return (byte)1; + + else + return (byte)0; + + } + + public static int toInt(byte[] b, int offset) { + + int value = 0; + for (int i = 0; i<4; i++) + value = (value << 8) + (b[i + offset] & 0xff); + + return value; + + } + + public static int to3Bytes(byte[] b, int offset) { + + int value = 0; + for (int i = 0; i<3; i++) + value = (value << 8) + (b[i + offset] & 0xff); + + return value; + + } + + public static long toLong(byte[] b, int offset) { + + long value = 0; + /* http://stackoverflow.com/questions/1026761/how-to-convert-a-byte-array-to-its-numeric-value-java */ + for (int i = 0; i<8; i++) + value = (value << 8) + (b[i + offset] & 0xff); + + + return value; + } + + public static UUID toUUID(byte[] b, int offset) { + + byte[] most = Utils.cutArray(b, 8, offset); + byte[] least = Utils.cutArray(b, 8, offset+8); + + return new UUID(toLong(most, 0), toLong(least, 0)); + } + + public static short toShort(byte[] b, int offset) { + + short value = 0; + for (int i = 0; i<2; i++) + value = (short)((value << 8) + (b[i + offset] & 0xff)); + + return value; + } + + public static boolean toBoolean(byte b) throws ReloadException{ + + if (b==1) + return true; + + else if (b==0) + return false; + + else + throw new NotTrueNorFalseReloadException(); + } + + public static boolean toBoolean(byte b[]) throws ReloadException{ + + return toBoolean(b[0]); + } + + public static byte[] cutArray(byte[] b, int size, int offset) { + + byte value[] = new byte[size]; + for (int i=0; i < size; i++) { + value[i] = b[offset+i]; + } + + return value; + } + + public static byte[] cutArray(byte[] b, int offset){ + + return cutArray(b, b.length-offset, offset); + + } + + public static boolean equals(byte[] array1, byte[] array2){ + + if(array1.length != array2.length) + return false; + + for (int i=0; i Math.pow(2, 24)-1) + throw new WrongLengthReloadException(); + } + + else{ + + type = ConfigUpdateType.valueOf(data[0]); + length = Utils.toInt(data, 1); + + if(length > Math.pow(2, 24)-1) + throw new WrongLengthReloadException(); + + switch(type.getBytes()){ + + case 1: + //config_data = new Opaque(24, data, 5); + config_data = Utils.cutArray(data, length, 5); + break; + + case 2: + + byte[] kindData = Utils.cutArray(data, length, 5); + + int num = Algorithm.counter(2, kindData, 0); + + kinds = new KindDescription[num]; + + for (int offset=0, i=0; i Math.pow(2, 24)-1) + throw new WrongLengthReloadException(); + + } + + public byte[] getBytes() throws IOException{ + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + baos.write(type.getBytes()); + baos.write(Utils.toByte(length)); + + switch(type.getBytes()){ + + case 1: + + baos.write(config_data); + break; + + case 2: + + for (int i=0; i + + + + public KindDescription (byte[] data, boolean upper) throws ReloadException{ // Upper call [llamada de los niveles superiores] + + if(upper) + this.data = new Opaque(16, data); + + else + this.data = new Opaque(16, data, 0); + + } + + + public byte[] getBytes() throws IOException{ + + return data.getBytes(); + + } + + + } \ No newline at end of file diff --git a/reload/Forwarding/ForwardingAndLinkInterface.java b/reload/Forwarding/ForwardingAndLinkInterface.java new file mode 100644 index 0000000..f9c0e1c --- /dev/null +++ b/reload/Forwarding/ForwardingAndLinkInterface.java @@ -0,0 +1,532 @@ + package reload.Forwarding; + + import reload.Message.Message; + import reload.Message.Forwarding.DestinationType; + import reload.Common.*; + import reload.Common.Error.*; + import reload.Common.Exception.*; + import reload.Forwarding.Request.*; + import reload.Forwarding.Ping.*; + import reload.Forwarding.Config.*; + import reload.Forwarding.Task.*; + import reload.Link.*; + import reload.dev2dev.*; + import java.util.*; + import java.net.InetAddress; + +/** +* ForwardingAndLinkInterface class is the interface of the Forwarding & Link Management module. +* @author Malosa +* @version 0.1 +*/ + + public class ForwardingAndLinkInterface{ + + private int port; // TCP port for THIS node + private boolean first; // This is the first node in the overlay + + private ForwardingCheck fc; + private XML configuration; + private ForwardingThread thread; + + private LinkInterface[] client; + private LinkInterface server; + + private String olp; // Overlay Link Protocol + + public SendData sendData; + public boolean updateIntialization; // Flag for receiving first update from AP + public boolean joinIntialization; // Flag for receiving update after join from AP + + + /** + * Establishes the Forwarding & Link Management module. + * @param port the port used by RELOAD + * @param first if this is the first node to initialize in the overlay + */ + public ForwardingAndLinkInterface(int port, boolean first) throws Exception{ + + this.port = port; + this.first = first; + + fc = new ForwardingCheck(configuration, first); + configuration = new XML(); + thread = new ForwardingThread(); + + client = new LinkInterface[134]; + + olp = configuration.getOverlayLinkProtocol(); + + sendData = new SendData(); + updateIntialization = false; + joinIntialization = false; + + } + + /** + * Initiates the Forwarding & Link Management module. It is called after the constructor. + * @return true if it could start and connect to the Admitting Peer + */ + public boolean start() throws Exception{ + + Initialization ini = new Initialization(fc, configuration, olp, first); + NodeId AP = ini.initiate(); + + if(AP == null) + return false; + + server = new LinkInterface(olp, port); + + createThreads(); + + ForwardingLoop loop = new ForwardingLoop(fc, server); + loop.start(); + + if(!first){ + + synchronized(this){ + + wait(); + + Thread.currentThread().sleep(50); + Module.tpi.createJoin(AP); + + joinIntialization = true; + + wait(); + + Thread.currentThread().sleep(50); // We wait so UpdateAns is sent first + Module.tpi.createUpdate(); // ALL NODES + + wait(); + + } + + } + + return true; + + } + + private void createThreads() throws Exception{ + + if(!first) + createClientThread(0); // Client thread numLink=0 (AP link) + + Module.falm.getForwardingThread().start(); // Task thread + Module.tpi.getTopologyThread().start(); // Task thread + Module.si.getStorageThread().start(); // Task thread + + } + + /** + * Creates a new Client thread (ReloadThread). + * @param numLink the link number + */ + public void createClientThread(int numLink) throws Exception{ + + ReloadThread ct = new ReloadThread(fc, client[numLink], Module.tpi.connectionTable.getNode(numLink, true)); + ct.start(); + + } + + /** + * It forms a Client connection, adding a new entry in the connection table and creating a new LinkInterface object. + * @param id the NodeId of the peer + * @param ip the IP address of the peer + * @return connection number or -1 if it failed + */ + public int createConnection(NodeId id, IpAddressPort ip) throws Exception{ + + int numLink; + + try{ + + numLink = Module.tpi.connectionTable.addEntry(id, ip, true); + + client[numLink] = new LinkInterface(olp, ip); + + } + catch (java.net.ConnectException ce){ + System.err.println("Failed to create conection to node "+ip.getAddress()+":"+ip.getPort()+"."); + return -1; + } + catch (java.net.SocketException se){ + System.err.println("Failed to create conection to node "+ip.getAddress()+":"+ip.getPort()+"."); + return -1; + } + + return numLink; + + } + + /** + * Method to be called from Message Transport when it receives an Attach Request message. + * @param msg_body Attach Request message to decode + * @param node peer which the message comes from (not the creator, just the last hop) + * @return the response (Attach Answer) to the request + */ + public byte[] attach_req(byte[] msg_body, NodeId node) throws Exception{ + + AttachReqAns req = new AttachReqAns(msg_body); + + IpAddressPort IP = req.getCandidates(0).getAddressPort(); //If public address, 0 + + + AttachReqAns ans = new AttachReqAns(false, new IpAddressPort(Nat.myIP, port)); // We do not ask for the routing table + + + if(!Module.tpi.connectionTable.isDirectlyConnected(node)){ + + int num = Module.tpi.connectionTable.addEntry(node, IP, false); + + if(req.getSendUpdate()) + Module.tpi.createUpdate(node, num, false, (byte)3, true); // full + } + + else + if(req.getSendUpdate()) + Module.tpi.createUpdate(node, (byte)3); + + return ans.getBytes(); + + } + + /** + * Method to be called from Message Transport when it receives a Ping Request message. + * @param msg_body Ping Request message to decode + * @return the response (Ping Answer) to the request + */ + public byte[] ping_req(byte[] msg_body) throws Exception{ + + PingReq req = new PingReq(msg_body, false); // Lower level + + int paddingLength = req.getPaddingLength(); // Not used + + long response_id = new Random().nextLong(); + + long time = 0; // Pending + + PingAns ans = new PingAns(response_id, time); + + return ans.getBytes(); + + } + + /** + * Method to be called from Message Transport when it receives an App Attach Request message. + * @param msg_body Attach Request message to decode + * @param ID peer which the message comes from (not the creator, just the last hop) + * @return the response (App Attach Answer) to the request + */ + public byte[] app_attach_req(byte[] msg_body, NodeId ID) throws Exception{ + + AppAttachReq req = new AppAttachReq(msg_body); + + IpAddressPort ip_port = req.getCandidates(0).getAddressPort(); //If public address, 0 + + short application = req.getApplication(); + if(false) + throw new ErrorForbidden(); // No application is supported + if(application != 5060) + throw new UnimplementedReloadException("Other applications than SIP"); + + InetAddress toAddr = ip_port.getAddress(); + short toPort = ip_port.getPort(); + + InetAddress fromAddr = InetAddress.getLocalHost(); + short fromPort = Module.falm.getPort(); + + TextClientInterface tci = new TextClientInterface(fromAddr, toAddr, fromPort, toPort, Nat.uri); + + tci.start(); + + + AppAttachAns ans = new AppAttachAns(new IpAddressPort(Nat.myIP, port), application); + + return ans.getBytes(); + + } + + /** + * Method to be called from Message Transport when it receives a Config Update Request message. + * @param msg_body Config Update Request message to decode + * @return the response (Config Update Answer) to the request + */ + public byte[] config_update_req(byte[] msg_body) throws Exception{ + + ConfigUpdateReq req = new ConfigUpdateReq(msg_body, false); // Lower level + + ConfigUpdateType type = req.getType(); + + byte[] config_data; + KindDescription[] kind; + + if(type == ConfigUpdateType.config) + config_data = req.getConfigData(); + + + + else if(type == ConfigUpdateType.kind) + kind = req.getKinds(); + + + else + throw new WrongTypeReloadException(); + + ConfigUpdateAns ans = new ConfigUpdateAns(); + + return ans.getBytes(); + + } + + /** + * Creates an Attach Task. + * @param node1 array of nodes to be attached + * @param node2 array of nodes to be attached + * @param initialization true if node is initializating + */ + public void createAttachRoute(NodeId[] node1, NodeId[] node2, boolean initialization){ + + AttachRouteTask task = new AttachRouteTask(thread, node1, node2, initialization); + + synchronized(thread){ + + boolean empty = thread.isEmpty(); + + thread.add(task); + + if(empty) + thread.notify(); + + } + + } + + /** + * Creates an App Attach Task. + * @param node NodeId to connect to + * @param application the app code + */ + public void createAppAttach(NodeId node, short application){ + + AppAttachTask task = new AppAttachTask(thread, node, application); + + synchronized(thread){ + + boolean empty = thread.isEmpty(); + + thread.add(task); + + if(empty) + thread.notify(); + + } + + } + + /** + * Creates an Attach Task. + * @param node1 array of nodes to be attached + * @param node2 array of nodes to be attached + * @param node3 array of nodes to be attached + * @param initialization true if node is initializating + */ + public void createAttachRoute(NodeId[] node1, NodeId[] node2, NodeId[] node3, boolean initialization){ + + AttachRouteTask task = new AttachRouteTask(thread, node1, node2, node3, initialization); + + synchronized(thread){ + + boolean empty = thread.isEmpty(); + + thread.add(task); + + if(empty) + thread.notify(); + + } + + } + + /** + * Creates an Attach Task. + * @param fingers array of fingers to be attached + * @param initialization true if node is initializating + */ + public void createAttachRoute(NodeId[] fingers, boolean initialization){ // Fingers + + AttachRouteTask task = new AttachRouteTask(thread, fingers, initialization); + + synchronized(thread){ + + boolean empty = thread.isEmpty(); + + thread.add(task); + + if(empty) + thread.notify(); + + } + + } + + /** + * Creates an Attach Task for fingers (create connections at 180º, 90º, etc). + */ + public void createAttachFingersRoute(){ // Fingers + + AttachRouteTask task = new AttachRouteTask(thread); + + synchronized(thread){ + + boolean empty = thread.isEmpty(); + + thread.add(task); + + if(empty) + thread.notify(); + + } + + } + + /** + * Sends a message to the network. + * @param data_msg the message (a whole RELOAD structure) + * @param num_link the link number + * @param cli true if connection is client, false if is server + */ + public void send(boolean cli, int num_link, byte[] data_msg) throws Exception{ + + if(cli) + client[num_link].send(data_msg); + else + server.send(num_link, data_msg); + + } + + /** + * Sends a message to the network. + * @param message a Message structure + */ + public void send(Message message) throws Exception{ + + Id FdestID = message.getDestinationId()[0]; // NodeId or ResourceId + DestinationType type = FdestID.getType(); + + int num_link; + boolean Bclient; + + if(type == DestinationType.node && Module.tpi.connectionTable.isDirectlyConnected((NodeId)FdestID)){ + Bclient = Module.tpi.connectionTable.isClient(FdestID); + num_link = Module.tpi.connectionTable.getNumLink(FdestID, Bclient); + } + + else{ + NodeId nextHop = Module.tpi.route(FdestID); + Bclient = Module.tpi.connectionTable.isClient(nextHop); + num_link = Module.tpi.connectionTable.getNumLink(nextHop, Bclient); + } + + if(type == DestinationType.node && server.bootstrapIsConnected((NodeId)FdestID)){ + Bclient = false; + num_link = server.getBootstrapNumLink((NodeId)FdestID); + } + + byte[] data_msg = message.getBytes(); + + if(Bclient) + client[num_link].send(data_msg); + else + server.send(num_link, data_msg); + + } + + /** + * Creates a ping attach (ping will be done to all nodes directly connected). + */ + public void pingAllNodes(){ + + PingTask task = new PingTask(thread); + + synchronized(thread){ + + boolean empty = thread.isEmpty(); + + thread.add(task); + + if(empty) + thread.notify(); + + } + + } + + /** + * Closes the specified connection. + * @param numLink the link number + * @param cli true if connection is client, false if is server + */ + public void close(int numLink, boolean cli) throws Exception{ + + if(cli){ + NodeId node = Module.tpi.connectionTable.getNode(numLink, cli); + Module.tpi.connectionTable.delete(numLink, cli); + Module.tpi.routingTable.delete(node); + client[numLink].close(); + } + + else{ + + if(numLink < 1000){ + NodeId node = Module.tpi.connectionTable.getNode(numLink, cli); + Module.tpi.connectionTable.delete(numLink, cli); + Module.tpi.routingTable.delete(node); + } + + else + server.deleteBootstrap(numLink); + + server.close(numLink); + } + + } + + public void closeServer() throws java.io.IOException{ + + server.close(); + + } + + /** + * Returns port. + * @return the TCP or UDP port + */ + public short getPort(){ + + return (short)port; + + } + + /** + * Returns configuration. + * @return the XML configuration data + */ + public XML getConfiguration(){ + + return configuration; + + } + + /** + * Returns the forwarding thread. + * @return the ForwardingThread object + */ + public ForwardingThread getForwardingThread(){ + + return thread; + + } + + } \ No newline at end of file diff --git a/reload/Forwarding/ForwardingCheck.java b/reload/Forwarding/ForwardingCheck.java new file mode 100644 index 0000000..dd2dca1 --- /dev/null +++ b/reload/Forwarding/ForwardingCheck.java @@ -0,0 +1,146 @@ + package reload.Forwarding; + + import reload.Message.*; + import reload.Message.Forwarding.DestinationType; + import reload.Common.*; + import reload.Common.Exception.*; + import java.util.*; + import java.net.InetAddress; + + public class ForwardingCheck{ + + private XML configuration; + private boolean first; + + public ForwardingCheck(XML configuration, boolean first) throws Exception{ // New connection + + this.configuration = configuration; + this.first = first; + + } + + public boolean checkMessage(Message message, NodeId peer) throws Exception{ + + Id[] destID = message.getDestinationId(); // NodeId or ResourceId + + NodeId thisID = Module.tpi.routingTable.getThisNode(); + NodeId previousID = Module.tpi.routingTable.getPredecessor(0); + + + if(thisID == null){ // First message received + + if(destID.length == 1 && destID[0].getType() == DestinationType.node && !((NodeId)destID[0]).isWildcard()) + return true; + else + return false; // Silently DROPPED + } + + + if(previousID == null && Module.tpi.routingTable.getSuccessor(0) != null) // Two nodes in the overlay + previousID = Module.tpi.routingTable.getSuccessor(0); + + + if(previousID == null){ // Not yet part of the Overlay or only node in the Overlay + + if(destID.length == 1) + return checkResponsibleId(destID, thisID, message, null); + else + return false; // Silently DROPPED + } + + + if(Module.tpi.routingTable.isResponsible(destID[0])) // Responsible ID + return checkResponsibleId(destID, thisID, message, peer); + + else // Other ID + return checkOtherId(destID, thisID, message, peer); + + + } + + public boolean checkMessage(Message message) throws Exception{ // Only usable if the peer is joining + + NodeId thisID = Module.tpi.routingTable.getThisNode(); + NodeId previousID = Module.tpi.routingTable.getPredecessor(0); + + if(thisID == null || previousID == null) + return checkMessage(message, null); + else + throw new WrongTypeReloadException(); + + } + + private boolean checkResponsibleId(Id[] destID, NodeId thisID, Message message, NodeId peer) throws Exception{ + + if(destID[0].getType() == DestinationType.resource){ // ResourceID + + if(destID.length == 1) + return true; + else + return false; // Silently DROPPED + + } + + else if(destID[0].getType() == DestinationType.node){ // NodeID + + if(((NodeId)destID[0]).isWildcard()) + return true; + + + if(destID[0].equals(thisID)){ + + if(destID.length == 1) + return true; + + else{ // length != 1 + + message.deleteFirstId(); + if(message.decTTL()){ + message.addVia(peer); + Module.falm.send(message); + } + else + {}// TTL ERROR MESSAGE + + return false; + + } + + } + + else // Not equals this ID + + return false; // Silently DROPPED UNLESS CLIENT. + + } + + else + throw new WrongTypeReloadException(); + + } + + private boolean checkOtherId(Id[] destID, NodeId thisID, Message message, NodeId peer) throws Exception{ + + if(destID[0].getType() == DestinationType.node || destID[0].getType() == DestinationType.resource){ // NodeID or ResourceID + + if(message.decTTL()){ + message.addVia(peer); + Module.falm.send(message); + } + else + {}// TTL error message + + return false; + + } + + else if(destID[0].getType() == DestinationType.opaque_id_type) + throw new UnimplementedReloadException("Compressed Via List."); + + + else + throw new WrongTypeReloadException(); + + } + + } \ No newline at end of file diff --git a/reload/Forwarding/ForwardingLoop.java b/reload/Forwarding/ForwardingLoop.java new file mode 100644 index 0000000..320e56b --- /dev/null +++ b/reload/Forwarding/ForwardingLoop.java @@ -0,0 +1,42 @@ + package reload.Forwarding; + + import reload.Link.LinkInterface; + + + public class ForwardingLoop extends Thread { + + private ForwardingCheck fc; + private LinkInterface server; + + + public ForwardingLoop(ForwardingCheck fc, LinkInterface server){ + + this.fc = fc; + this.server = server; + + } + + public void run(){ + + while(true){ + + ReloadThread st = new ReloadThread(fc, server); + st.start(); + + synchronized(st){ + try{ + st.wait(); + } + catch(InterruptedException e){ + + e.printStackTrace(); + + } + } + + } + + } + + } + diff --git a/reload/Forwarding/ForwardingThread.java b/reload/Forwarding/ForwardingThread.java new file mode 100644 index 0000000..fd89cc4 --- /dev/null +++ b/reload/Forwarding/ForwardingThread.java @@ -0,0 +1,110 @@ +package reload.Forwarding; + +import reload.Message.*; +import reload.Forwarding.Task.*; +import reload.Common.*; +import reload.Common.Exception.*; + +import java.util.*; + +public class ForwardingThread extends Thread { + + private ArrayDeque queue; + + private boolean empty; + + + public ForwardingThread(){ + + queue = new ArrayDeque(); + + empty = true; + + } + + public void run() { + + + while(true){ + + synchronized(this){ + + if(isEmpty()){ + + try{ + wait(); + } + catch(InterruptedException e){ + + e.printStackTrace(); + + } + + } + } + + try{ + + ForwardingTask task = queue.getFirst(); + TaskType type = task.getType(); + + switch(type.getValue()){ + + case 0: + throw new WrongTypeReloadException("Undefined Task"); + case 1: + PingTask ping = (PingTask)task; + ping.start(); + break; + case 2: + AttachRouteTask attach = (AttachRouteTask)task; + attach.start(); + break; + case 3: + AppAttachTask app_attach = (AppAttachTask)task; + app_attach.start(); + break; + default: + throw new WrongTypeReloadException(); + } + + queue.removeFirst(); + + } + catch(Exception e){ + + e.printStackTrace(); + + } + + + } + + } + + public boolean isEmpty(){ + + return queue.size() == 0; + + } + + public void add(ForwardingTask task){ + + queue.add(task); + + } + + public ForwardingTask getFirst(){ + + return queue.getFirst(); + + } + + public void setMessage(Message message){ + + queue.getFirst().setMessage(message); + + } + +} + diff --git a/reload/Forwarding/Initialization.java b/reload/Forwarding/Initialization.java new file mode 100644 index 0000000..318b7ef --- /dev/null +++ b/reload/Forwarding/Initialization.java @@ -0,0 +1,136 @@ +package reload.Forwarding; + +import reload.Message.*; +import reload.Forwarding.Request.*; +import reload.Link.*; +import reload.Topology.*; +import reload.Common.*; +import reload.Common.Exception.*; +import java.net.InetAddress; + +public class Initialization{ + + private ForwardingCheck fc; + private XML configuration; + private String olp; + + private LinkInterface bootstrapConn; + private boolean first; + + + public Initialization (ForwardingCheck fc, XML configuration, String olp, boolean first){ + + this.fc = fc; + this.configuration = configuration; + this.olp = olp; + this.first = first; + + } + + + public NodeId initiate() throws Exception{ + + InetAddress address = InetAddress.getLocalHost(); + + NodeId thisNodeId = (NodeId)Module.tpi.generateNewId(address, true); + + System.out.println("My Node-ID: " + thisNodeId.print()); + + + Module.tpi.routingTable.setThisNode(thisNodeId); + + if(first) + return new NodeId(); + + if(attachReqAP()){ + + NodeId AP = attachAnsAP(); + bootstrapConn.close(); // Closes bootstrap connection + Module.falm.updateIntialization = true; // Ready to receive update + return AP; + } + + else + return null; + + } + + private boolean attachReqAP() throws Exception{ + + + IpAddressPort[] bootstrap = configuration.getBootstrapNode(); + + byte[] nodeIDbytes = Module.tpi.routingTable.getThisNode().getId(); + ResourceId ApRId = new ResourceId(nodeIDbytes, true); + ApRId.add(1); // Admitting Peer Resource-ID + + try{ + + boolean exit = false; + + for (int i=0; !exit; i++){ + + + try{ + bootstrapConn = new LinkInterface(olp, bootstrap[i]); + } + catch (java.net.ConnectException ce){ + System.err.println("Failed to Attach to boostrap node "+bootstrap[i].getAddress()+":"+bootstrap[i].getPort()+"."); + continue; + } + catch (java.net.SocketException se){ + System.err.println("Failed to Attach to boostrap node "+bootstrap[i].getAddress()+":"+bootstrap[i].getPort()+"."); + continue; + } + + exit = true; + Nat.setMyIp(bootstrap[i]); + + } + + } + catch (ArrayIndexOutOfBoundsException aioobe){ + + System.err.println("Failed to Attach. No boostrap node available."); + return false; + + } + + + AttachReqAns req = new AttachReqAns(true, new IpAddressPort(Nat.myIP, Module.falm.getPort())); // We ask for the routing table + + byte[] msg_body = req.getBytes(); + + short code = 3; // AttachReq + + byte[] data_msg = new Message(msg_body, ApRId, Module.tpi.routingTable.getThisNode(), code).getBytes(); + + bootstrapConn.send(data_msg); + + return true; + + } + + private NodeId attachAnsAP() throws Exception{ + + byte[] response = bootstrapConn.receive(); + Message message = new Message(response); + + if(!fc.checkMessage(message) || message.getMessageCode() != 4) + throw new WrongPacketReloadException(4); + + NodeId ApNId = message.getSourceNodeId(); + + + byte[] msg_body = message.getMessageBody(); + AttachReqAns ans = new AttachReqAns(msg_body); + + IpAddressPort IpAp = ans.getCandidates(0).getAddressPort(); //If public addresses, 0 + + Module.falm.createConnection(ApNId, IpAp); + + return ApNId; + + } + +} \ No newline at end of file diff --git a/reload/Forwarding/Ping/PingAns.java b/reload/Forwarding/Ping/PingAns.java new file mode 100644 index 0000000..08b39e3 --- /dev/null +++ b/reload/Forwarding/Ping/PingAns.java @@ -0,0 +1,51 @@ + package reload.Forwarding.Ping; + + import java.io.*; + import reload.Common.*; + + public class PingAns{ + + + private long response_id; + private long time; + + + + public PingAns (long response_id, long time){ + + this.response_id = response_id; + this.time = time; + + } + + public PingAns (byte[] data) throws IOException{ + + response_id = Utils.toLong(data, 0); + time = Utils.toLong(data, 8); + + } + + public byte[] getBytes() throws IOException{ + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + baos.write(Utils.toByte(response_id)); + baos.write(Utils.toByte(time)); + + return baos.toByteArray(); + + } + + public long getResponseId(){ + + return response_id; + + } + + public long getTime(){ + + return time; + + } + + } \ No newline at end of file diff --git a/reload/Forwarding/Ping/PingReq.java b/reload/Forwarding/Ping/PingReq.java new file mode 100644 index 0000000..d4ef252 --- /dev/null +++ b/reload/Forwarding/Ping/PingReq.java @@ -0,0 +1,43 @@ + package reload.Forwarding.Ping; + + import java.io.*; + import reload.Common.*; + import reload.Common.Exception.*; + + public class PingReq{ + + + private Opaque padding; //<0..2^16-1> + + private byte[] def_data = new byte[]{0,0,0,0,0,0,0,0}; + + + public PingReq () throws ReloadException{ //upper call [llamada de los niveles superiores] + + padding = new Opaque(16, def_data); + + } + + public PingReq (byte[] data, boolean upper) throws ReloadException{ //upper call [llamada de los niveles superiores] + + if(upper) + padding = new Opaque(16, data); + + else + padding = new Opaque(16, data, 0); + + } + + public byte[] getBytes() throws IOException{ + + return padding.getBytes(); + + } + + public int getPaddingLength(){ + + return padding.getContent().length; + + } + + } \ No newline at end of file diff --git a/reload/Forwarding/ReloadThread.java b/reload/Forwarding/ReloadThread.java new file mode 100644 index 0000000..1590b79 --- /dev/null +++ b/reload/Forwarding/ReloadThread.java @@ -0,0 +1,161 @@ +package reload.Forwarding; + +import reload.Message.*; +import reload.Link.*; +import reload.Common.*; +import reload.Common.Exception.*; + +public class ReloadThread extends Thread { + + private ForwardingCheck fc; + private LinkInterface li; + private NodeId peer; + private boolean server; + + private int num; // Only if server + private boolean bootstrap; // Only if server + + + public ReloadThread(ForwardingCheck fc, LinkInterface li, NodeId peer){ // Client + + this.fc = fc; + this.li = li; + this.peer = peer; + server = false; + + } + + public ReloadThread(ForwardingCheck fc, LinkInterface li){ // Server + + this.fc = fc; + this.li = li; + server = true; + + } + + public void run() { + + try{ + + if(server){ + + num = li.newConnection(); + if(num == -1) + return; + if(num >= 1000) + bootstrap = true; + + synchronized(this){ + notify(); // Next thread is unlocked + } + + peer = Module.tpi.connectionTable.getNode(num, false); + + } + + if(Module.falm.sendData.contains(num, !server)){ + + byte[] data = Module.falm.sendData.getData(num, !server); + + send(data); + + Module.falm.sendData.delete(num, !server); + + } + } + + catch(Exception e){ + + e.printStackTrace(); + + } + + + while(true){ + + try{ + + byte[] received = null; + try{ + received = receive(); + } + catch(java.io.EOFException e){ + + if(bootstrap) + li.deleteBootstrap(num); + else{ + Module.tpi.connectionTable.delete(peer, !server); + Module.tpi.routingTable.delete(peer); + } + return; + } + catch(java.io.IOException io){ + + if(bootstrap) + li.deleteBootstrap(num); + else{ + Module.tpi.connectionTable.delete(peer, !server); + Module.tpi.routingTable.delete(peer); + } + return; + } + + Message message = new Message(received); + + if(peer == null && bootstrap){ + peer = message.getSourceNodeId(); + + li.addBootstrapNode(peer, num); + } + + + if(fc.checkMessage(message, peer)){ + + if(message.isAns()) + + Module.msg.processAns(message); + + else{ // isReq + + byte[] response = Module.msg.processReq(message, peer); + + if(num != -1 || (num == -1 && server && Module.tpi.routingTable.getPredecessor(0) == null)) + send(response); + else + throw new ReloadException("Mensaje erróneo con num -1"); + + } + } + } + catch(Exception e){ + + e.printStackTrace(); + + } + + } + + } + + private byte[] receive() throws Exception{ + + if(server) + return li.receive(num); + + else + return li.receive(); + + } + + private void send(byte[] data) throws Exception{ + + if(server) + li.send(num, data); + + else + li.send(data); + + } + +} + diff --git a/reload/Forwarding/Request/AppAttachAns.java b/reload/Forwarding/Request/AppAttachAns.java new file mode 100644 index 0000000..36af6da --- /dev/null +++ b/reload/Forwarding/Request/AppAttachAns.java @@ -0,0 +1,124 @@ + package reload.Forwarding.Request; + + import java.io.*; + import reload.Common.*; + import reload.Common.Exception.*; + + public class AppAttachAns{ + + private Opaque ufrag; //<0..2^8-1> + private Opaque password; //<0..2^8-1> + private short application; + private Opaque role; //<0..2^8-1> + + private short cand_length; + private IceCandidate[] candidates; //<0..2^16-1> + + + public AppAttachAns (IpAddressPort addr_port, short application) throws Exception{ // Empty, NAT not supported + + ufrag = new Opaque(8, new byte[0]); + password = new Opaque(8, new byte[0]); + role = new Opaque(8, new byte[0]); + this.application = application; + + cand_length = 0; + + candidates = new IceCandidate[1]; + candidates[0] = new IceCandidate(addr_port, OverlayLinkType.UNDEFINED, new byte[0], 0, new IceExtension[0]); + + for (int i=0; i Math.pow(2, 16)-1) + throw new WrongLengthReloadException(); + + } + + public AppAttachAns (byte[] ufrag, byte[] password, short application, byte[] role, IceCandidate[] candidates) throws Exception{ + + this.ufrag = new Opaque(8, ufrag); + this.password = new Opaque(8, password); + this.application = application; + this.role = new Opaque(8, role); + + this.candidates = candidates; + + for (int i=0; i Math.pow(2, 16)-1) + throw new WrongLengthReloadException(); + + } + + public AppAttachAns (byte[] data) throws Exception{ + + + ufrag = new Opaque(8, data, 0); + int offset = ufrag.getBytes().length; + + password = new Opaque(8, data, offset); + offset += password.getBytes().length; + + application = Utils.toShort(data, offset); + offset += 2; + + role = new Opaque(8, data, offset); + offset += role.getBytes().length; + + cand_length = Utils.toShort(data, offset); + offset += 2; + + data = Utils.cutArray(data, cand_length, offset); + offset = 0; + + int num = Algorithm.AttachCounter(data); + + candidates = new IceCandidate[num]; + + for (int i=0; i + private Opaque password; //<0..2^8-1> + private short application; + private Opaque role; //<0..2^8-1> + + private short cand_length; + private IceCandidate[] candidates; //<0..2^16-1> + + + public AppAttachReq (IpAddressPort addr_port, short application) throws Exception{ // Empty, NAT not supported + + ufrag = new Opaque(8, new byte[0]); + password = new Opaque(8, new byte[0]); + role = new Opaque(8, new byte[0]); + this.application = application; + + cand_length = 0; + + candidates = new IceCandidate[1]; + candidates[0] = new IceCandidate(addr_port, OverlayLinkType.UNDEFINED, new byte[0], 0, new IceExtension[0]); + + for (int i=0; i Math.pow(2, 16)-1) + throw new WrongLengthReloadException(); + + } + + public AppAttachReq (byte[] ufrag, byte[] password, short application, byte[] role, IceCandidate[] candidates) throws Exception{ + + this.ufrag = new Opaque(8, ufrag); + this.password = new Opaque(8, password); + this.application = application; + this.role = new Opaque(8, role); + + this.candidates = candidates; + + for (int i=0; i Math.pow(2, 16)-1) + throw new WrongLengthReloadException(); + + } + + public AppAttachReq (byte[] data) throws Exception{ + + + ufrag = new Opaque(8, data, 0); + int offset = ufrag.getBytes().length; + + password = new Opaque(8, data, offset); + offset += password.getBytes().length; + + application = Utils.toShort(data, offset); + offset += 2; + + role = new Opaque(8, data, offset); + offset += role.getBytes().length; + + cand_length = Utils.toShort(data, offset); + offset += 2; + + data = Utils.cutArray(data, cand_length, offset); + offset = 0; + + int num = Algorithm.AttachCounter(data); + + candidates = new IceCandidate[num]; + + for (int i=0; i + private Opaque password; //<0..2^8-1> + private Opaque role; //<0..2^8-1> + + private short cand_length; + private IceCandidate[] candidates; //<0..2^16-1> + private boolean send_update; + + + public AttachReqAns (boolean send_update, IpAddressPort addr_port) throws Exception{ // Empty, NAT not supported + + ufrag = new Opaque(8, new byte[0]); + password = new Opaque(8, new byte[0]); + role = new Opaque(8, new byte[0]); + + cand_length = 0; + + candidates = new IceCandidate[1]; + candidates[0] = new IceCandidate(addr_port, OverlayLinkType.UNDEFINED, new byte[0], 0, new IceExtension[0]); + this.send_update = send_update; + + for (int i=0; i Math.pow(2, 16)-1) + throw new WrongLengthReloadException(); + + } + + public AttachReqAns (byte[] ufrag, byte[] password, byte[] role, IceCandidate[] candidates, boolean send_update) throws Exception{ + + this.ufrag = new Opaque(8, ufrag); + this.password = new Opaque(8, password); + this.role = new Opaque(8, role); + + this.candidates = candidates; + this.send_update = send_update; + + for (int i=0; i Math.pow(2, 16)-1) + throw new WrongLengthReloadException(); + + } + + public AttachReqAns (byte[] data) throws Exception{ + + ufrag = new Opaque(8, data, 0); + int offset = ufrag.getBytes().length; + + password = new Opaque(8, data, offset); + offset += password.getBytes().length; + + role = new Opaque(8, data, offset); + offset += role.getBytes().length; + + cand_length = Utils.toShort(data, offset); + offset += 2; + + data = Utils.cutArray(data, cand_length+1, offset); + offset = 0; + + int num = Algorithm.AttachCounter(Utils.cutArray(data, cand_length, 0)); + + candidates = new IceCandidate[num]; + + for (int i=0; i + private int priority; + private CandType type; + + private IpAddressPort rel_addr_port; + + private short ext_length; + private IceExtension[] extensions; //<0..2^16-1> + + + + public IceCandidate(IpAddressPort addr_port, OverlayLinkType overlay_link, byte[] foundation, int priority, IceExtension[] extensions) throws Exception{ + + this.addr_port = addr_port; + this.overlay_link = overlay_link; + this.foundation = new Opaque(8, foundation); + this.priority = priority; + + type = CandType.host; // Default type ¿? + + this.extensions = extensions; + + for (int i=0; i Math.pow(2, 16)-1) + throw new WrongLengthReloadException(); + + } + + public IceCandidate(IpAddressPort addr_port, OverlayLinkType overlay_link, byte[] foundation, int priority, CandType type, IceExtension[] extensions) throws Exception{ + + this(addr_port,overlay_link, foundation, priority, extensions); + + this.type = type; + + if (type == CandType.relay) + throw new WrongTypeReloadException("No IPAddressPort specified (required for CandType relay)"); + + } + + public IceCandidate(IpAddressPort addr_port, OverlayLinkType overlay_link, byte[] foundation, int priority, IpAddressPort rel_addr_port, IceExtension[] extensions) throws Exception{ + + this.addr_port = addr_port; + this.overlay_link = overlay_link; + this.foundation = new Opaque(8, foundation); + this.priority = priority; + + this.rel_addr_port = rel_addr_port; + + type = CandType.relay; + + this.extensions = extensions; + + for (int i=0; i Math.pow(2, 16)-1) + throw new WrongLengthReloadException(); + + } + + public IceCandidate(byte[] data) throws Exception { + + addr_port = new IpAddressPort(data); + int offset = addr_port.getBytes().length; + + overlay_link = OverlayLinkType.valueOf(data[offset]); + offset++; + + foundation = new Opaque(8, data, offset); + offset += foundation.getBytes().length; + + priority = Utils.toInt(data, offset); + offset += 4; + + type = CandType.valueOf(data[offset]); + offset++; + + switch(type.getBytes()){ + + case 1: + break; + case 2: + break; + case 3: + break; + case 4: + rel_addr_port = new IpAddressPort(Utils.cutArray(data, offset)); + offset += rel_addr_port.getBytes().length; + } + + ext_length = Utils.toShort(data, offset); + offset += 2; + + byte[] dataExt = Utils.cutArray(data, ext_length, offset); + offset = 0; + + int num = Algorithm.counter(2, dataExt, 0); + + num = num/2; // The number of IceExtensions is the half of the Opaques count (an IceExtension structure contains two Opaques) + + extensions = new IceExtension[num]; + + for (int i=0; i + private Opaque value; //<0..2^16-1> + + + + public IceExtension (byte[] name, byte[] value) throws ReloadException{ + + this.name = new Opaque(16, name); + this.value = new Opaque(16, value); + + } + + public IceExtension (byte[] data) throws Exception{ + + + name = new Opaque(16, data, 0); + + int offset = name.getBytes().length; + + name = new Opaque(16, data, offset); + + } + + public byte[] getBytes() throws IOException{ + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + baos.write(name.getBytes()); + baos.write(value.getBytes()); + + return baos.toByteArray(); + + } + + } \ No newline at end of file diff --git a/reload/Forwarding/Request/OverlayLinkType.java b/reload/Forwarding/Request/OverlayLinkType.java new file mode 100644 index 0000000..9065534 --- /dev/null +++ b/reload/Forwarding/Request/OverlayLinkType.java @@ -0,0 +1,51 @@ + package reload.Forwarding.Request; + + /* Constructor: + OverlayLinkType type = OverlayLinkType.valueOf(1); + OverlayLinkType type = OverlayLinkType.DTLS_UDP_SR; + */ + + public enum OverlayLinkType { + UNDEFINED( "undefined", (byte)-1), + reservedOverlayLink( "reserved Overlay Link", (byte)0), + DTLS_UDP_SR( "DTLS-UDP-SR", (byte)1), + DTLS_UDP_SR_NO_ICE( "DTLS-UDP-SR-NO-ICE", (byte)3), + TLS_TCP_FH_NO_ICE( "TLS-TCP-FH-NO-ICE", (byte)4); + + + + final String name; + final byte value; + + private OverlayLinkType(String name, byte value) { + this.name = name; + this.value = value; + } + + + public static OverlayLinkType valueOf(int value) { + OverlayLinkType type = UNDEFINED; + switch (value) { + case 0: + type = reservedOverlayLink; + break; + case 1: + type = DTLS_UDP_SR; + break; + case 3: + type = DTLS_UDP_SR_NO_ICE; + break; + case 4: + type = TLS_TCP_FH_NO_ICE; + } + + return type; + } + + public byte getBytes(){ + + return value; + + } + + } \ No newline at end of file diff --git a/reload/Forwarding/SendData.java b/reload/Forwarding/SendData.java new file mode 100644 index 0000000..a0f75be --- /dev/null +++ b/reload/Forwarding/SendData.java @@ -0,0 +1,105 @@ + + package reload.Forwarding; + + import reload.Common.*; + import java.util.*; + import reload.Common.Exception.*; + + public class SendData{ + + private ArrayList num_link; + private ArrayList client; + private ArrayList data; + + + public SendData(){ + + num_link = new ArrayList(); + client = new ArrayList(); + data = new ArrayList(); + + } + + public synchronized void add(int num_link, boolean client, byte[] data){ + + this.num_link.add(num_link); + this.client.add(client); + this.data.add(data); + + } + + public byte[] getData(int num, boolean client) throws ReloadException{ + + int pos1 = num_link.indexOf(num); + int pos2 = num_link.lastIndexOf(num); + + if(pos1 == -1) + return null; + + if(pos1 == pos2){ + boolean cli = this.client.get(pos1); + + if(cli==client) + return data.get(pos1); + else + return null; + } + + if(this.client.get(pos1) == client) + return data.get(pos1); + else if (this.client.get(pos2) == client) + return data.get(pos2); + else + throw new ReloadException("Incorrect data, duplicate boolean value."); + + } + + public synchronized boolean delete(int num, boolean client) throws ReloadException{ + + int pos1 = num_link.indexOf(num); + int pos2 = num_link.lastIndexOf(num); + + if(pos1 == -1) + return false; + + if(pos1 == pos2){ + boolean cli = this.client.get(pos1); + + if(cli==client){ + remove(pos1); + return true; + } + else + return false; + } + + if(this.client.get(pos1) == client) + remove(pos1); + else if (this.client.get(pos2) == client) + remove(pos2); + else + throw new ReloadException("Incorrect data, duplicate boolean value."); + + return true; + + } + + public void remove(int pos){ + + num_link.remove(pos); + client.remove(pos); + data.remove(pos); + + } + + public boolean contains(int num, boolean client) throws ReloadException{ + + if(getData(num, client) == null) + return false; + + else + return true; + + } + + } \ No newline at end of file diff --git a/reload/Forwarding/Task/AppAttachTask.java b/reload/Forwarding/Task/AppAttachTask.java new file mode 100644 index 0000000..e9fc6bc --- /dev/null +++ b/reload/Forwarding/Task/AppAttachTask.java @@ -0,0 +1,81 @@ + package reload.Forwarding.Task; + + import reload.Message.*; + import reload.Forwarding.*; + import reload.Forwarding.Request.*; + import reload.Common.*; + import reload.Common.Exception.*; + import reload.dev2dev.*; + import java.net.InetAddress; + + public class AppAttachTask extends ForwardingTask{ + + private NodeId dest; + private short application; + + public AppAttachTask(ForwardingThread thread, NodeId dest, short application){ + + super(thread); + + type = TaskType.app_attach; + + this.dest = dest; + this.application = application; + + } + + public void start() throws Exception{ + + IpAddressPort ip_port = send_receive(dest, application); + + InetAddress toAddr = ip_port.getAddress(); + short toPort = ip_port.getPort(); + + InetAddress fromAddr = InetAddress.getLocalHost(); + short fromPort = Module.falm.getPort(); + + TextClientInterface tci = new TextClientInterface(fromAddr, toAddr, fromPort, toPort, Nat.uri); + + tci.start(); + + } + + public IpAddressPort send_receive(NodeId dest, short application) throws Exception{ + + + AppAttachReq req = new AppAttachReq(new IpAddressPort(Nat.myIP, Module.falm.getPort()), application); + + byte[] msg_body = req.getBytes(); + + short code = 29; // AppAttachReq + + Module.msg.send(msg_body, code, dest); + + Message mes = receive(); + + code = mes.getMessageCode(); + + if (code != 30) // AppAttachAns + throw new WrongPacketReloadException(4); + + + msg_body = mes.getMessageBody(); + + AppAttachAns ans = new AppAttachAns(msg_body); + + IpAddressPort IPdest = ans.getCandidates(0).getAddressPort(); //If public addresses, 0 + + short app = ans.getApplication(); + + if(application != app) + throw new WrongTypeReloadException("Application not match"); + + if(application != 5060) + throw new UnimplementedReloadException("Other applications than SIP"); + + return IPdest; + + } + + } + diff --git a/reload/Forwarding/Task/AttachRouteTask.java b/reload/Forwarding/Task/AttachRouteTask.java new file mode 100644 index 0000000..0ad8072 --- /dev/null +++ b/reload/Forwarding/Task/AttachRouteTask.java @@ -0,0 +1,216 @@ +package reload.Forwarding.Task; + +import reload.Message.*; +import reload.Forwarding.*; +import reload.Forwarding.Request.*; +import reload.Common.*; +import reload.Common.Exception.*; +import java.net.InetAddress; + +public class AttachRouteTask extends ForwardingTask{ + + private NodeId dest; + private NodeId[] nodes1; + private NodeId[] nodes2; + private NodeId[] nodes3; + + private boolean fingers; + + private boolean initialization; // Special case for initialization + + + public AttachRouteTask(ForwardingThread thread, NodeId[] nodes1, NodeId[] nodes2, boolean initialization){ + + super(thread); + + type = TaskType.attach_route; + + this.nodes1 = nodes1; + this.nodes2 = nodes2; + nodes3 = null; + + fingers = false; + + this.initialization = initialization; + + } + + public AttachRouteTask(ForwardingThread thread, NodeId[] nodes1, NodeId[] nodes2, NodeId[] nodes3, boolean initialization){ + + this(thread, nodes1, nodes2, initialization); + + this.nodes3 = nodes3; + + } + + public AttachRouteTask(ForwardingThread thread, NodeId[] fingers, boolean initialization){ + + super(thread); + + type = TaskType.attach_route; + + nodes1 = fingers; + nodes2 = null; + nodes3 = null; + + this.fingers = true; + + this.initialization = initialization; + + } + + public AttachRouteTask(ForwardingThread thread){ // Fingers + + super(thread); + + type = TaskType.attach_route; + + nodes1 = null; + nodes2 = null; + nodes3 = null; + + this.fingers = true; + + initialization = false; + + } + + public void start() throws Exception{ + + + if(fingers){ + + if(nodes1 == null){ + + for (int i=Module.tpi.routingTable.getCurrentFingerLength(); i node = Module.tpi.routingTable.getNodes(); + + for(int i=0; i + Copyright (C) <2013> Contact: isaias.martinezy@uah.es + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA \ No newline at end of file diff --git a/reload/Link/BoostrapList.java b/reload/Link/BoostrapList.java new file mode 100644 index 0000000..4bb3132 --- /dev/null +++ b/reload/Link/BoostrapList.java @@ -0,0 +1,171 @@ + package reload.Link; + + import java.util.*; + import java.net.InetAddress; + import reload.Common.*; + + public class BoostrapList{ + + private ArrayList address; // IpAddressPort + private ArrayList node; + private ArrayList num_link; + + public BoostrapList(){ + + address = new ArrayList(); + node = new ArrayList(); + num_link = new ArrayList(); + + } + + public synchronized int addEntry(InetAddress addr) throws Exception{ + + IpAddressPort ip = new IpAddressPort(addr, 0); + + byte[] onlyAddress = ip.getAddressBytes(); + int num = getFirstNumber(); + + address.add(onlyAddress); + node.add(null); + num_link.add(num); + + return num; + + } + + public synchronized void addNode(NodeId node, int num){ + + int pos = num_link.indexOf(num); + + this.node.set(pos, node.getBytes()); + + } + + public int getNumLink(InetAddress addr) throws Exception{ + + IpAddressPort ip = new IpAddressPort(addr, 0); + + byte[] Bip = ip.getAddressBytes(); + + int pos = addrIndexOf(Bip); + + if(pos == -1) + return -1; + else + return num_link.get(pos); + + } + + public int getNumLink(NodeId id){ + + byte[] Bid = id.getId(); + + int pos = nodeIndexOf(Bid); + + if(pos == -1) + return -1; + else + return num_link.get(pos); + + } + + public boolean exists(NodeId id){ + + byte[] Bid = id.getId(); + + int pos = nodeIndexOf(Bid); + + if(pos == -1) + return false; + else + return true; + + } + + public synchronized boolean delete(int num){ + + int del_num = -1; + + del_num = num_link.indexOf(num); + + if(del_num == -1) + return false; + + try{ + remove(del_num); + } + catch(IndexOutOfBoundsException e){ + return false; + } + + return true; + + } + + private void remove(int num){ + + address.remove(num); + node.remove(num); + num_link.remove(num); + + } + + public synchronized IpAddressPort getAddressPort(int num) throws Exception{ + + int pos = num_link.indexOf(num); + + if(pos == -1) + return null; + else + return new IpAddressPort(address.get(pos), 0); // No remote port + + } + + private synchronized int addrIndexOf(byte[] addr){ + + for (int i=0; i + + private DestinationType destination_type; + + + public DestinationData(NodeId node_id){ + + this.node_id = node_id; + destination_type = DestinationType.node; + } + + public DestinationData(ResourceId resource_id){ + + this.resource_id = resource_id; + destination_type = DestinationType.resource; + } + + public DestinationData(Id id) throws ReloadException{ + + destination_type = id.getType(); + + if(destination_type == DestinationType.node) + node_id = (NodeId)id; + + else if(destination_type == DestinationType.resource) + resource_id = (ResourceId)id; + + else + throw new WrongTypeReloadException(); + + } + + public DestinationData(Opaque opaque_id){ + + this.opaque_id = opaque_id; + destination_type = DestinationType.opaque_id_type; + } + + public DestinationData(byte[] data, DestinationType destination_type) throws Exception{ + + this.destination_type = destination_type; + + switch(destination_type.getBytes()){ + + case 1: + node_id = new NodeId(data, false); // Lower + break; + case 2: + resource_id = new ResourceId(data, false); // Lower + break; + case 3: + opaque_id = new Opaque(8, data, 0); + break; + default: + throw new WrongTypeReloadException(); + + } + } + + public byte[] getBytes() throws Exception{ + + switch(destination_type.getBytes()){ + + case 1: + return node_id.getBytes(); + case 2: + return resource_id.getBytes(); + case 3: + return opaque_id.getBytes(); + default: + throw new WrongTypeReloadException(); + + } + } + + public NodeId getNodeId() throws ReloadException{ + + if(destination_type == DestinationType.node) + return node_id; + else + throw new WrongTypeReloadException(); + + } + + public ResourceId getResourceId() throws ReloadException{ + + if(destination_type == DestinationType.resource) + return resource_id; + else + throw new WrongTypeReloadException(); + + } + + public Id getId() throws ReloadException{ + + if(destination_type == DestinationType.resource) + return resource_id; + + if(destination_type == DestinationType.node) + return node_id; + + throw new WrongTypeReloadException(); + + } + + public byte[] getCompressedId() throws Exception{ + + if(destination_type == DestinationType.opaque_id_type) + return opaque_id.getContent(); + else + throw new WrongTypeReloadException(); + + } + + } \ No newline at end of file diff --git a/reload/Message/Forwarding/DestinationType.java b/reload/Message/Forwarding/DestinationType.java new file mode 100644 index 0000000..79a6a15 --- /dev/null +++ b/reload/Message/Forwarding/DestinationType.java @@ -0,0 +1,59 @@ + package reload.Message.Forwarding; + +/* public class DestinationType { + public static final byte reserved = ((byte)0); + public static final byte node = ((byte)1); + public static final byte resource = ((byte)2); + public static final byte compressed = ((byte)3); + } + */ + + /* Constructor: + DestinationType type = DestinationType.valueOf(1); + DestinationType type = DestinationType.node; + */ + + public enum DestinationType { + UNDEFINED( "undefined", (byte)-1), + reserved( "reserved", (byte)0), + node( "node", (byte)1), + resource( "resource", (byte)2), + opaque_id_type("opaque id type",(byte)3); + + + final String name; + final byte value; + + private DestinationType(String name, byte value) { + this.name = name; + this.value = value; + } + + + public static DestinationType valueOf(int value) { + DestinationType type = UNDEFINED; + switch (value) { + case 0: + type = reserved; + break; + case 1: + type = node; + break; + case 2: + type = resource; + break; + case 3: + type = opaque_id_type; + break; + } + + return type; + } + + public byte getBytes(){ + + return value; + + } + + } \ No newline at end of file diff --git a/reload/Message/Forwarding/ForwardingHeader.java b/reload/Message/Forwarding/ForwardingHeader.java new file mode 100644 index 0000000..b9598c1 --- /dev/null +++ b/reload/Message/Forwarding/ForwardingHeader.java @@ -0,0 +1,276 @@ + package reload.Message.Forwarding; + + import java.util.*; + import java.io.*; + import reload.Common.*; + + public class ForwardingHeader { + + + private int relo_token; + private int overlay; + private short configuration_sequence; + private byte version; + private byte ttl; + private int fragment; + private int length; // Length of the whole message, including this header + private long transaction_id; + private int max_response_length; + private short via_list_length; + private short destination_list_length; + private short options_length; + private Destination[] via_list; // Multiple Destination + private Destination[] destination_list; // Multiple Destination + private ForwardingOptions[] options; // Multiple options + + + + //DESTINATION[] ONLY + public ForwardingHeader(int overlay, short configuration_sequence, byte ttl, int fragment, + int max_response_length, Destination[] destination_list) throws Exception{ + + Random r = new Random(); + + this.relo_token=0xd2454c4f; + this.overlay=overlay; + this.configuration_sequence=configuration_sequence; + this.version=0xa; // 1.0 + this.ttl=ttl; // 100 normalmente + this.fragment=fragment; + this.transaction_id=r.nextLong(); // Random + this.max_response_length=max_response_length; + + this.destination_list = destination_list; + for (int i=0; i 0){ + for (int i=0; i 0){ + for (int i=0; i 0){ + for (int i=0; i initial_ttl) + throw new ReloadError("Error_TTL_Exceeded"); + + + int fragment = 0xC0000000; //No fragments + int max_response_length = 0; + + + Destination destination_list[] = new Destination[dest.length]; + + for(int i=0; i + + public ErrorResponse (short error_code, byte[] error_info) throws ReloadException{ + + this.error_code = error_code; + this.error_info = new Opaque(16, error_info); + + } + + public ErrorResponse (short error_code) throws ReloadException{ // error_info is optional + + this.error_code = error_code; + this.error_info = new Opaque(16, new byte[0]); + + } + + public ErrorResponse (byte[] data) throws ReloadException{ + + this.error_code = Utils.toShort(data, 0); + this.error_info = new Opaque(16, data, 2); + + } + + public byte[] getBytes() throws IOException{ + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + baos.write(Utils.toByte(error_code)); + baos.write(error_info.getBytes()); + + return baos.toByteArray(); + + } + + public short getErrorCode(){ + + return error_code; + + } + + public byte[] getErrorInfo() throws IOException{ + + return error_info.getContent(); + + } + + } \ No newline at end of file diff --git a/reload/Message/MessageCont/MessageContents.java b/reload/Message/MessageCont/MessageContents.java new file mode 100644 index 0000000..9ce5c64 --- /dev/null +++ b/reload/Message/MessageCont/MessageContents.java @@ -0,0 +1,102 @@ + package reload.Message.MessageCont; + + import java.io.*; + import reload.Common.*; + import reload.Common.Exception.*; + + public class MessageContents{ + + + private short message_code; + private Opaque message_body; //<0..2^32-1> + private int extensions_length; + private MessageExtension[] extensions; //<0..2^32-1> + + + + public MessageContents (short message_code, byte[] message_body, MessageExtension[] extensions) throws Exception{ + + this.message_code = message_code; + this.message_body = new Opaque(32, message_body); + + this.extensions = extensions; + + for (int i=0; i Math.pow(2, 32)-1) + throw new WrongLengthReloadException(); + + } + + public MessageContents (short message_code, byte[] message_body) throws ReloadException{ + + this.message_code = message_code; + this.message_body = new Opaque(32, message_body); + this.extensions = new MessageExtension[0]; + + extensions_length = 0; + + } + + public MessageContents (byte[] data) throws Exception { + + message_code = Utils.toShort(data, 0); + int offset = 2; + + message_body = new Opaque(32, data, offset); + offset += message_body.getBytes().length; + + extensions_length = Utils.toInt(data, offset); + offset += 4; + + data = Utils.cutArray(data, extensions_length, offset); + offset = 0; + + int num = Algorithm.counter(4, data, 3); + + extensions = new MessageExtension[num]; + + for (int i=0; i + + + + public MessageExtension (MessageExtensionType type, boolean critical, byte[] extension_contents) throws ReloadException{ + + this.type=type; + this.critical=critical; + this.extension_contents = new Opaque(32, extension_contents); + + } + + public MessageExtension (byte[] data) throws ReloadException{ + + type = MessageExtensionType.valueOf(Utils.toShort(data, 0)); + critical = Utils.toBoolean(data[2]); + extension_contents = new Opaque(32, data, 3); + + } + + public byte[] getBytes() throws IOException{ + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + baos.write(type.getBytes()); + baos.write(Utils.toByte(critical)); + baos.write(extension_contents.getBytes()); + + return baos.toByteArray(); + + } + + public MessageExtensionType getType(){ + + return type; + + } + + public boolean getCritical(){ + + return critical; + + } + + public byte[] getExtensionContents() throws IOException{ + + return extension_contents.getContent(); + + } + + } \ No newline at end of file diff --git a/reload/Message/MessageCont/MessageExtensionType.java b/reload/Message/MessageCont/MessageExtensionType.java new file mode 100644 index 0000000..15b716b --- /dev/null +++ b/reload/Message/MessageCont/MessageExtensionType.java @@ -0,0 +1,51 @@ + package reload.Message.MessageCont; + + import reload.Common.Utils; + + + /* Constructor: + MessageExtensionType type = MessageExtensionType.valueOf(0); + MessageExtensionType type = MessageExtensionType.reservedMessagesExtension; + */ + + public enum MessageExtensionType { + UNDEFINED( "undefined", (short)-1), + reservedMessagesExtension("reserved messages extension", (short)0); + + + final String name; + final short value; + + private MessageExtensionType(String name, short value) { + + this.name = name; + this.value = value; + } + + + public static MessageExtensionType valueOf(int value) { + + MessageExtensionType type = UNDEFINED; + + switch (value) { + case 0: + type = reservedMessagesExtension; + break; + } + + return type; + } + + public short getValue(){ + + return value; + + } + + public byte[] getBytes(){ + + return Utils.toByte(value); + + } + + } \ No newline at end of file diff --git a/reload/Message/MessageStructure.java b/reload/Message/MessageStructure.java new file mode 100644 index 0000000..9a4e0ef --- /dev/null +++ b/reload/Message/MessageStructure.java @@ -0,0 +1,89 @@ + package reload.Message; + + import java.util.*; + import java.io.*; + import reload.Common.*; + import reload.Common.Exception.*; + import reload.Message.Forwarding.*; + import reload.Message.MessageCont.*; + import reload.Message.Security.*; + import reload.Message.Security.TLS.*; + + + public class MessageStructure { + + private ForwardingHeader fh; + private MessageContents mc; + private SecurityBlock sb; + + + + public MessageStructure(ForwardingHeader fh, MessageContents mc, SecurityBlock sb) throws Exception{ //Standard message + + this.fh=fh; + this.mc=mc; + this.sb=sb; + + setSize(); + + } + + public MessageStructure(byte[] data) throws Exception{ + + fh = new ForwardingHeader(data); + + int length = fh.getLength(); + data = Utils.cutArray(data, length, 0); + + int fhLength = fh.getBytes().length; + + if(fhLength >= length) + throw new WrongLengthReloadException("Inconsistent length field."); + + mc = new MessageContents(Utils.cutArray(data, fhLength)); + + int mcLength = mc.getBytes().length; + + sb = new SecurityBlock(Utils.cutArray(data, fhLength+mcLength)); + + } + + private void setSize() throws Exception{ + + int sizeFH = fh.getBytes().length; + int sizeMC = mc.getBytes().length; + int sizeSB = sb.getBytes().length; + + fh.setLength(sizeFH+sizeMC+sizeSB); + + } + + public byte[] getBytes() throws Exception{ + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + baos.write(fh.getBytes()); + baos.write(mc.getBytes()); + baos.write(sb.getBytes()); + + return baos.toByteArray(); + + } + + public ForwardingHeader getForwardingHeader(){ + + return fh; + } + + public MessageContents getMessageContents(){ + + return mc; + } + + public SecurityBlock getSecurityBlock(){ + + return sb; + } + + + } \ No newline at end of file diff --git a/reload/Message/MessageTransport.java b/reload/Message/MessageTransport.java new file mode 100644 index 0000000..e0da961 --- /dev/null +++ b/reload/Message/MessageTransport.java @@ -0,0 +1,799 @@ + package reload.Message; + + import java.util.*; + import java.io.*; + import reload.Common.*; + import reload.Common.Error.*; + import reload.Common.Exception.*; + import reload.Forwarding.*; + import reload.Topology.TopologyPluginInterface; + + import reload.Forwarding.Request.*; + import reload.Storage.*; + import reload.Topology.*; + + import reload.Message.MessageCont.*; + + import java.net.InetAddress; + +/** +* MessageTransport class is the interface of the MessageTransport module. +* @author Malosa +* @version 0.1 +*/ + public class MessageTransport { + + private int port; + private boolean first; + + /** + * Establishes the Message Transport module. + * @param port the port used by RELOAD + * @param first if this is the first node to initialize in the overlay + */ + public MessageTransport(int port, boolean first) throws Exception{ + + this.port = port; + this.first = first; + + Module.tpi = new TopologyPluginInterface(); + + Module.falm = new ForwardingAndLinkInterface(port, first); + + } + + /** + * Initiates the Message Transport module. It is called after the constructor. + * @return true if it could start and connect to the Admitting Peer + */ + public boolean start() throws Exception{ // New node in the overlay + + return Module.falm.start(); + + } + + /** + * Sends a message. + * @param message a Message structure + */ + public void send(Message message) throws Exception{ + + Module.falm.send(message); + + } + + /** + * Sends a message. + * @param msg_body the message body (MESSAGE BODY field from the RELOAD structure) + * @param code the the message code (MESSAGE CODE field from the RELOAD structure) + * @param dest the the destination array (ResourceId[] or NodeId[] to form the DESTINATION LIST) + */ + public void send(byte[] msg_body, short code, Id[] dest) throws Exception{ + + Message msg = new Message(msg_body, dest, Module.tpi.routingTable.getThisNode(), code); + + Module.falm.send(msg); + + } + + /** + * Sends a message. + * @param msg_body the message body (MESSAGE BODY field from the RELOAD structure) + * @param code the the message code (MESSAGE CODE field from the RELOAD structure) + * @param dest the the destination (ResourceId or NodeId) + */ + public void send(byte[] msg_body, short code, Id dest) throws Exception{ + + this.send(msg_body, code, new Id[]{dest}); + + } + + /** + * Sends a message. + * @param msg_body the message body (MESSAGE BODY field from the RELOAD structure) + * @param code the the message code (MESSAGE CODE field from the RELOAD structure) + * @param dest the the destination array (ResourceId[] or NodeId[] to form the DESTINATION LIST) + * @param numLink the link number + * @param client true if connection is client, false if is server + */ + public void send(byte[] msg_body, short code, Id[] dest, int numLink, boolean client) throws Exception{ + + Message msg = new Message(msg_body, dest, Module.tpi.routingTable.getThisNode(), code); + + byte[] message = msg.getBytes(); + + Module.falm.send(client, numLink, message); + + } + + /** + * Sends a message. + * @param msg_body the message body (MESSAGE BODY field from the RELOAD structure) + * @param code the the message code (MESSAGE CODE field from the RELOAD structure) + * @param dest the the destination (ResourceId or NodeId) + * @param numLink the link number + * @param client true if connection is client, false if is server + */ + public void send(byte[] msg_body, short code, Id dest, int numLink, boolean client) throws Exception{ + + this.send(msg_body, code, new Id[]{dest}, numLink, client); + + } + + /** + * Processes a Request, method to be called from the Forwarding & Link Management module. + * @param message the Message structure + * @param peer peer which the message comes from (not the creator, just the last hop) + */ + public byte[] processReq(Message message, NodeId peer) throws Exception{ + + + short code = message.getMessageCode(); + + if(code >= 0x8000 && code <= 0xfffe) + throw new WrongTypeReloadException("reserved"); + + switch(code){ + case 1: + return probe_req(message, peer); + case 3: + return attach_req(message, peer); + case 5: + throw new WrongTypeReloadException("unused"); + case 7: + return store_req(message, peer); + case 9: + return fetch_req(message, peer); + case 11: + throw new WrongTypeReloadException("unused (was remove_req)"); + case 13: + return find_req(message, peer); + case 15: + return join_req(message, peer); + case 17: + return leave_req(message, peer); + case 19: + return update_req(message, peer); + case 21: + return route_query_req(message, peer); + case 23: + return ping_req(message, peer); + case 25: + return stat_req(message, peer); + case 27: + throw new WrongTypeReloadException("unused (was attachlite_req)"); + case 29: + return app_attach_req(message, peer); + case 31: + throw new WrongTypeReloadException("unused (was app_attachlite_req)"); + case 33: + return config_update_req(message, peer); + case 35: + return exp_a_req(message, peer); + case 37: + return exp_b_req(message, peer); + case (short)0xffff: + return error(message); + default: + throw new WrongTypeReloadException("invalid #" + code); + } + + } + + /** + * Processes an Answer, method to be called from the Forwarding & Link Management module. + * @param message the Message structure + */ + public void processAns(Message message) throws Exception{ + + + short code = message.getMessageCode(); + + if(code >= 0x8000 && code <= 0xfffe) + throw new WrongTypeReloadException("reserved"); + + switch(code){ + case 2: + case 16: + case 18: + case 20: + case 22: + TopologyThread tThread = Module.tpi.getFakeTopologyThread(); + tThread.setMessageAndNotify(message); + break; + case 4: + case 24: + case 30: + case 34: + ForwardingThread fThread = Module.falm.getForwardingThread(); + synchronized(fThread){ + fThread.setMessage(message); + fThread.notify(); + } + break; + case 6: + throw new WrongTypeReloadException("unused"); + case 8: + case 10: + case 14: + case 26: + StorageThread sThread = Module.si.getStorageThread(); + synchronized(sThread){ + sThread.setMessage(message); + sThread.notify(); + } + break; + case 12: + throw new WrongTypeReloadException("unused (was remove_ans)"); + case 28: + throw new WrongTypeReloadException("unused (was attachlite_req)"); + case 32: + throw new WrongTypeReloadException("unused (was app_attachlite_req)"); + case 36: + exp_a_ans(message); + case 38: + exp_b_ans(message); + case (short)0xffff: + error(message); + default: + throw new WrongTypeReloadException("invalid"); + + } + + } + + private byte[] probe_req(Message message, NodeId peer) throws Exception{ + + byte[] msg_body = message.getMessageBody(); + + byte[] ans_msg_body = Module.tpi.probe_req(msg_body); + + short code = 2; // ProbeAns + + NodeId[] via = message.getViaList(); + NodeId[] dest = createRoute(via, peer); + + Message msg = new Message(ans_msg_body, dest, Module.tpi.routingTable.getThisNode(), code); + return msg.getBytes(); + + } + + private byte[] attach_req(Message message, NodeId peer) throws Exception{ + + NodeId ID = message.getSourceNodeId(); + + byte[] msg_body = message.getMessageBody(); + + byte[] ans_msg_body = Module.falm.attach_req(msg_body, ID); + + short code = 4; //AttachAns + + NodeId[] via = message.getViaList(); + NodeId[] dest = createRoute(via, peer); + + Message msg = new Message(ans_msg_body, dest, Module.tpi.routingTable.getThisNode(), code); + return msg.getBytes(); + + } + + private byte[] store_req(Message message, NodeId peer) throws Exception{ + + byte[] msg_body = message.getMessageBody(); + + short code = 0; + byte[] ans_msg_body = null; + + try{ + ans_msg_body = Module.si.store_req(msg_body); + code = 8; // store_ans + } + catch(ErrorUnknownKind euk){ + + String mes = euk.getMessage(); + + String[] kinds = mes.split("-"); + KindId[] unknown = new KindId[kinds.length]; + + for (int i=0; i= 0x8000 && error_code <= 0xfffe) + throw new WrongTypeReloadException("reserved"); + + switch(error_code){ + case 1: + throw new WrongTypeReloadException("Unused"); + case 2: + error_Forbidden(error_info); + break; + case 3: + error_Not_Found(error_info); + break; + case 4: + error_Request_Timeout(error_info); + break; + case 5: + error_Generation_Counter_Too_Low(error_info); + break; + case 6: + error_Incompatible_with_Overlay(error_info); + break; + case 7: + error_Unsupported_Forwarding_Option(error_info); + break; + case 8: + error_Data_Too_Large(error_info); + break; + case 9: + error_Data_Too_Old(error_info); + break; + case 10: + error_TTL_Exceeded(error_info); + break; + case 11: + error_Message_Too_Large(error_info); + break; + case 12: + error_Unknown_Kind(error_info); + break; + case 13: + error_Unknown_Extension(error_info); + break; + case 14: + error_Response_Too_Large(error_info); + break; + case 15: + error_Config_Too_Old(error_info); + break; + case 16: + error_Config_Too_New(error_info); + break; + case 17: + error_In_Progress(error_info); + break; + case 18: + error_Exp_A(error_info); + break; + case 19: + error_Exp_B(error_info); + break; + case 20: + error_Invalid_Message(error_info); + break; + default: + throw new WrongTypeReloadException("invalid"); + + } + + } + + public void error_Forbidden(byte[] error_info){ // set all to private + + // Gestionar error + + } + + public void error_Not_Found(byte[] error_info){ + + // Gestionar error + + } + + public void error_Request_Timeout(byte[] error_info){ + + // Gestionar error + + } + + public void error_Generation_Counter_Too_Low(byte[] error_info){ + + // Gestionar error + + } + + public void error_Incompatible_with_Overlay(byte[] error_info){ + + // Gestionar error + + } + + public void error_Unsupported_Forwarding_Option(byte[] error_info){ + + // Gestionar error + + } + + public void error_Data_Too_Large(byte[] error_info){ + + // Gestionar error + + } + + public void error_Data_Too_Old(byte[] error_info){ + + // Gestionar error + + } + + public void error_TTL_Exceeded(byte[] error_info){ + + // Gestionar error + + } + + public void error_Message_Too_Large(byte[] error_info){ + + // Gestionar error + + } + + public void error_Unknown_Kind(byte[] error_info){ + + // Gestionar error + + } + + public void error_Unknown_Extension(byte[] error_info){ + + // Gestionar error + + } + + public void error_Response_Too_Large(byte[] error_info){ + + // Gestionar error + + } + + public void error_Config_Too_Old(byte[] error_info){ + + // Gestionar error + + } + + public void error_Config_Too_New(byte[] error_info){ + + // Gestionar error + + } + + public void error_In_Progress(byte[] error_info){ + + // Gestionar error + + } + + public void error_Exp_A(byte[] error_info){ + + // Gestionar error + + } + + public void error_Exp_B(byte[] error_info){ + + // Gestionar error + + } + + public void error_Invalid_Message(byte[] error_info){ + + // Gestionar error + + } + + private NodeId[] createRoute(NodeId[] via, NodeId peer){ + + NodeId[] route = new NodeId[via.length+1]; + + route[0] = peer; + + for(int i=1, j=via.length-1; i Math.pow(2, 16)-1) + throw new WrongLengthReloadException(); + } + + public SecurityBlock (byte[] data) throws Exception{ + + cert_length = Utils.toShort(data, 0); + + byte[] data_cert = Utils.cutArray(data, cert_length, 2); + int offset = 0; + + int num = Algorithm.counter(2, data_cert, 1); + + certificates = new GenericCertificate[num]; + + for (int i=0; i + + public Signature (SignatureAndHashAlgorithm algorithm, SignerIdentity identity, byte[] signature_value) throws ReloadException{ + + this.algorithm = algorithm; + this.identity = identity; + this.signature_value = new Opaque(16, signature_value); + + } + + public Signature (byte[] data) throws Exception{ + + algorithm = new SignatureAndHashAlgorithm(data); // Size: 2 bytes + identity = new SignerIdentity(Utils.cutArray(data, 2)); + + int lengthIdentity = identity.getBytes().length; + signature_value = new Opaque(16, data, lengthIdentity+2); + + } + + public byte[] getBytes() throws IOException{ + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + baos.write(algorithm.getBytes()); + baos.write(identity.getBytes()); + baos.write(signature_value.getBytes()); + + return baos.toByteArray(); + + } + + public SignerIdentity getIdentity(){ + + return identity; + + } + + + } \ No newline at end of file diff --git a/reload/Message/Security/SignerIdentity.java b/reload/Message/Security/SignerIdentity.java new file mode 100644 index 0000000..ff88d62 --- /dev/null +++ b/reload/Message/Security/SignerIdentity.java @@ -0,0 +1,69 @@ + package reload.Message.Security; + + import java.io.*; + import reload.Common.*; + import reload.Common.Exception.*; + + public class SignerIdentity{ + + + private SignerIdentityType identity_type; + private short length; + private SignerIdentityValue identity; + + + public SignerIdentity (SignerIdentityType identity_type, SignerIdentityValue identity) throws IOException{ + + this.identity_type = identity_type; + this.identity = identity; + + length = (short)(identity.getBytes().length); + + } + + public SignerIdentity (SignerIdentityType identity_type) { //SignerIdentityValue empty + + this.identity_type = identity_type; + length = 0; + this.identity = new SignerIdentityValue(); //Empty + + } + + public SignerIdentity (byte[] data) throws ReloadException { + + identity_type = SignerIdentityType.valueOf(data[0]); + length = Utils.toShort(data, 1); + + if (length > 0) + identity = new SignerIdentityValue(Utils.cutArray(data, length, 3), identity_type); + + else + identity = new SignerIdentityValue(); //Empty + + } + + public byte[] getBytes() throws IOException{ + + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + baos.write(identity_type.getBytes()); + baos.write(Utils.toByte(length)); + baos.write(identity.getBytes()); + + return baos.toByteArray(); + } + + public SignerIdentityType getType(){ + + return identity_type; + + } + + public SignerIdentityValue getValue(){ + + return identity; + + } + + } \ No newline at end of file diff --git a/reload/Message/Security/SignerIdentityType.java b/reload/Message/Security/SignerIdentityType.java new file mode 100644 index 0000000..2fb18e3 --- /dev/null +++ b/reload/Message/Security/SignerIdentityType.java @@ -0,0 +1,55 @@ + package reload.Message.Security; + + /* Constructor: + SignerIdentityType type = SignerIdentityType.valueOf(1); + SignerIdentityType type = SignerIdentityType.cert_hash; + */ + + public enum SignerIdentityType { + UNDEFINED( "undefined", "", (byte)-1), + reservedSignerIdentity("reservedsigneridentity", "Reserved Signer Identity", (byte)0), + cert_hash( "certhash", "Certificate Hash", (byte)1), + cert_hash_node_id( "certhashnodeid", "Certificate Hash NodeId", (byte)2), + none( "none", "None", (byte)3); + + + final String name; // not the standard signature algorithm name + // except the UNDEFINED, other names are defined + // by TLS 1.2 protocol + final String standardName; // the standard MessageDigest algorithm name + final byte value; + + + private SignerIdentityType(String name, String standardName, byte value) { + this.name = name; + this.standardName = standardName; + this.value = value; + } + + public static SignerIdentityType valueOf(int value) { + SignerIdentityType type = UNDEFINED; + switch (value) { + case 0: + type = reservedSignerIdentity; + break; + case 1: + type = cert_hash; + break; + case 2: + type = cert_hash_node_id; + break; + case 3: + type = none; + break; + } + + return type; + } + + public byte getBytes(){ + + return value; + + } + + } \ No newline at end of file diff --git a/reload/Message/Security/SignerIdentityValue.java b/reload/Message/Security/SignerIdentityValue.java new file mode 100644 index 0000000..ab5dbf9 --- /dev/null +++ b/reload/Message/Security/SignerIdentityValue.java @@ -0,0 +1,79 @@ + package reload.Message.Security; + + import java.io.*; + import reload.Message.Security.TLS.*; + import reload.Common.*; + import reload.Common.Exception.*; + + public class SignerIdentityValue{ + + + private HashAlgorithm hash_alg; // From TLS + private Opaque certificate_hash; // 8-bit. Two types + private SignerIdentityType identity_type; + + + public SignerIdentityValue (HashAlgorithm hash_alg, byte[] certificate_hash, SignerIdentityType identity_type) throws ReloadException{ + + if(identity_type == SignerIdentityType.cert_hash || identity_type == SignerIdentityType.cert_hash_node_id){ + this.hash_alg = hash_alg; + this.certificate_hash = new Opaque(8, certificate_hash); + } + + this.identity_type = identity_type; // Not a part of the Structure + + } + + public SignerIdentityValue(){ + + identity_type = SignerIdentityType.none; + + } + + public SignerIdentityValue (byte[] data, SignerIdentityType identity_type) throws ReloadException{ + + + if(identity_type == SignerIdentityType.cert_hash || identity_type == SignerIdentityType.cert_hash_node_id){ + hash_alg = HashAlgorithm.valueOf(data[0]); + certificate_hash = new Opaque(8, data, 1); + } + + this.identity_type = identity_type; // Not a part of the Structure + + } + + public byte[] getBytes() throws IOException{ + + byte ret[] = new byte[0]; // Empty + + switch(identity_type.getBytes()){ + + case 1: + + // We go to case 2 + + case 2: + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + baos.write(hash_alg.getBytes()); + baos.write(certificate_hash.getBytes()); + ret = baos.toByteArray(); + break; + + case 3: + + /* Empty */ + + } + + return ret; + + } + + public byte[] getCertificateHash(){ // Returns cert_hash and also cert_hast_node_id + + return certificate_hash.getContent(); + + } + + } \ No newline at end of file diff --git a/reload/Message/Security/TLS/HashAlgorithm.java b/reload/Message/Security/TLS/HashAlgorithm.java new file mode 100644 index 0000000..4672308 --- /dev/null +++ b/reload/Message/Security/TLS/HashAlgorithm.java @@ -0,0 +1,70 @@ + package reload.Message.Security.TLS; + + /* Constructor: + HashAlgorithm hash = HashAlgorithm.valueOf(1); + HashAlgorithm hash = HashAlgorithm.MD5; + */ + + public enum HashAlgorithm { + UNDEFINED("undefined", (byte)-1), + none( "none", (byte)0), + md5( "MD5", (byte)1), + sha1( "SHA-1", (byte)2), + sha224( "SHA-224", (byte)3), + sha256( "SHA-256", (byte)4), + sha384( "SHA-384", (byte)5), + sha512( "SHA-512", (byte)6); + + final String name; // Except the UNDEFINED, other names are defined + final byte value; // by TLS 1.2 protocol + + private HashAlgorithm(String name, byte value) { + + this.name = name; + this.value = value; + } + + public static HashAlgorithm valueOf(int value) { + + HashAlgorithm hash = UNDEFINED; + + switch (value) { + case 0: + hash = none; + break; + case 1: + hash = md5; + break; + case 2: + hash = sha1; + break; + case 3: + hash = sha224; + break; + case 4: + hash = sha256; + break; + case 5: + hash = sha384; + break; + case 6: + hash = sha512; + break; + } + + return hash; + } + + public byte getBytes(){ + + return value; + + } + + public String getName(){ + + return name; + + } + + } diff --git a/reload/Message/Security/TLS/SignatureAlgorithm.java b/reload/Message/Security/TLS/SignatureAlgorithm.java new file mode 100644 index 0000000..fdd6ab1 --- /dev/null +++ b/reload/Message/Security/TLS/SignatureAlgorithm.java @@ -0,0 +1,53 @@ + package reload.Message.Security.TLS; + + + /* Constructor: + SignatureAlgorithm alg = SignatureAlgorithm.valueOf(1); + SignatureAlgorithm alg = SignatureAlgorithm.rsa; + */ + + public enum SignatureAlgorithm { + UNDEFINED("undefined", (byte)-1), + anonymous("anonymous", (byte)0), + rsa( "RSA", (byte)1), + dsa( "DSA", (byte)2), + ecdsa( "ECDSA", (byte)3); + + final String name; // except the UNDEFINED, other names are defined + final byte value; // by TLS 1.2 protocol + + private SignatureAlgorithm(String name, byte value) { + + this.name = name; + this.value = value; + } + + static SignatureAlgorithm valueOf(int value) { + + SignatureAlgorithm sign = UNDEFINED; + switch (value) { + case 0: + sign = anonymous; + break; + case 1: + sign = rsa; + break; + case 2: + sign = dsa; + break; + case 3: + sign = ecdsa; + break; + } + + return sign; + } + + public byte getBytes(){ + + return value; + + } + + } + diff --git a/reload/Message/Security/TLS/SignatureAndHashAlgorithm.java b/reload/Message/Security/TLS/SignatureAndHashAlgorithm.java new file mode 100644 index 0000000..a2b4686 --- /dev/null +++ b/reload/Message/Security/TLS/SignatureAndHashAlgorithm.java @@ -0,0 +1,38 @@ + package reload.Message.Security.TLS; + + import java.io.*; + + + public class SignatureAndHashAlgorithm{ + + private HashAlgorithm hash; + private SignatureAlgorithm signature; + + + + public SignatureAndHashAlgorithm (HashAlgorithm hash, SignatureAlgorithm signature){ + + this.hash = hash; + this.signature = signature; + + } + + public SignatureAndHashAlgorithm (byte[] data){ + + hash = HashAlgorithm.valueOf(data[0]); + signature = SignatureAlgorithm.valueOf(data[1]); + + } + + public byte[] getBytes() throws IOException{ + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + baos.write(hash.getBytes()); + baos.write(signature.getBytes()); + + return baos.toByteArray(); + + } + + } \ No newline at end of file diff --git a/reload/ReloadInterface.java b/reload/ReloadInterface.java new file mode 100644 index 0000000..0eee5e2 --- /dev/null +++ b/reload/ReloadInterface.java @@ -0,0 +1,223 @@ + +package reload; + +import reload.Common.*; +import reload.Common.Exception.*; +import reload.Message.MessageTransport; +import reload.Storage.StorageInterface; +import reload.Storage.Data.*; + +/** +* ReloadInterface class is the interface of the RELOAD protocol. +* @author Malosa +* @version 0.1 +*/ +public class ReloadInterface{ + + private int port; + private boolean first; + +/** + * Establishes the RELOAD protocol. + * @param port the port used by RELOAD + * @param first if this is the first node to initialize in the overlay + */ + public ReloadInterface(int port, boolean first) throws Exception{ + + this.port = port; + this.first = first; + + Module.si = new StorageInterface(); + + Module.msg = new MessageTransport(port, first); + + } + +/** + * Establishes the RELOAD protocol, specifying a common DataModel. + * @param port the port used by RELOAD + * @param first if this is the first node to initialize in the overlay + * @param dataModel only this data model will be available + */ + public ReloadInterface(int port, boolean first, DataModel dataModel) throws Exception{ + + this.port = port; + this.first = first; + + Module.si = new StorageInterface(dataModel); + + Module.msg = new MessageTransport(port, first); + + } + +/** + * Initializes the RELOAD protocol. It is called after the constructor. + * @return true if it could start and connect to the Admitting Peer + */ + public boolean start() throws Exception{ + + return Module.msg.start(); + + } + + public boolean commonCommand(String read) throws Exception{ // true=exit, false=normal + + if(read.length() > 4) + read = read.substring(0, 4); + + switch(read.toLowerCase()){ + + case "": + break; + case "hi": + case "hell": + System.out.println("Hello!"); + break; + case "id": + System.out.println(Module.tpi.routingTable.printId()); + break; + case "neig": + System.out.println(Module.tpi.routingTable.printNeighbors()); + break; + case "fing": + System.out.println(Module.tpi.routingTable.printFingers()); + break; + case "dict": + System.out.println(Module.si.dictionary.print()); + break; + case "ping": + Module.falm.pingAllNodes(); + Thread.currentThread().sleep(150); + break; + case "attf": + Module.falm.createAttachFingersRoute(); + break; + case "help": + System.out.println("fetch \"uri\": It fetchs the info of the \"uri\""); + System.out.println("remove \"uri\": It removes the info of the \"uri\". Check source code"); + System.out.println("sip \"uri\": It opens connection with the \"uri\""); + System.out.println("id: It shows Node-ID"); + System.out.println("neig: It shows neighbours"); + System.out.println("fing: It shows fingers"); + System.out.println("dict: It shows dictionary"); + System.out.println("ping: It pings all nodes"); + System.out.println("attf: It attaches a finger"); + System.out.println("bye: It makes node to leave the overlay"); + System.out.println("help: It shows this information"); + break; + case "leav": + case "exit": + case "quit": + case "bye": + Module.tpi.createLeave(); + return true; + default: + System.out.println("Unknown command. Use \"help\" to show the diffente commands"); + } + + return false; + + } + +/** + * Stores a dictionary entry in the overlay. + * @param resource the Resource-ID where it will be stored + * @param kind the kind-ID for the storage + * @param data the data to be stored + * @param key the key of the dictionary entry + */ + public void storeDictionary(ResourceId resource, KindId kind, Opaque[] data, Opaque[] key) throws Exception{ + + Module.si.storeDictionary(resource, null, (byte)0, kind, data, key); + + } + +/** + * Stores an array entry in the overlay. + * @param resource the Resource-ID where it will be stored + * @param kind the kind-ID for the storage + * @param data the data to be stored + * @param index the index of the array entry + */ + public void storeArray(ResourceId resource, KindId kind, Opaque[] data, int[] index) throws ReloadException{ + + Module.si.storeArray(resource, kind, data, index); + + } + +/** + * Stores a single entry in the overlay. + * @param resource the Resource-ID where it will be stored + * @param kind the kind-ID for the storage + * @param data the data to be stored + */ + public void storeSingle(ResourceId resource, KindId kind, Opaque data) throws ReloadException{ + + Module.si.storeSingle(resource, kind, data); + + } + +/** + * Fetches some dictionary entries from the overlay. + * @param resource the Resource-ID where it will be fetched + * @param kind the kind-ID for the fetch + * @param key the keys of the dictionary entries + */ + public DataStructure[] fetchDictionary(ResourceId resource, KindId kind, Opaque[] key) throws Exception{ + + return Module.si.fetchDictionary(resource, kind, key); + + } + +/** + * Creates an App Attach Task. + * @param node NodeId to connect to + * @param application the app code + */ + public void appAttach(NodeId node, short application){ + + Module.falm.createAppAttach(node, application); + + } + +/** + * Removes some dictionary entries from the overlay. + * @param resource the Resource-ID where it will be removed + * @param kind the kind-ID to remove + * @param key the keys of the dictionary entries to be removed + */ + public void removeDictionary(ResourceId resource, KindId kind, Opaque[] key) throws Exception{ + + boolean[] exists = new boolean[key.length]; + + for(int i=0; i + + private String contact_prefs; //<0..2^16-1> + + private short destination_length; + private Destination[] destination_list; //<0..2^16-1> + + private SipRegistrationType type; + + + public SipRegistrationData (String uri) throws ReloadException{ + + this.uri = uri; //new Opaque(16, uri); + + string_length = (short)uri.length(); + + if(string_length > Math.pow(2, 16)-1) + throw new WrongLengthReloadException(); + + type = SipRegistrationType.sip_registration_uri; + + } + + public SipRegistrationData (String contact_prefs, Destination[] destination_list) throws Exception{ + + this.contact_prefs = contact_prefs; //new Opaque(16, contact_prefs); + + string_length = (short)contact_prefs.length(); + + if(string_length > Math.pow(2, 16)-1) + throw new WrongLengthReloadException(); + + this.destination_list = destination_list; + + for (int i=0; i Math.pow(2, 16)-1) + throw new WrongLengthReloadException(); + + type = SipRegistrationType.sip_registration_route; + + } + + public SipRegistrationData (byte[] data, SipRegistrationType type) throws Exception{ + + this.type = type; + + string_length = Utils.toShort(data, 0); + + switch(type.getValue()){ + + case 1: + + uri = new String(Utils.cutArray(data, string_length, 2), "US-ASCII"); //new Opaque(16, data, 0); + break; + + case 2: + + contact_prefs = new String(Utils.cutArray(data, string_length, 2), "US-ASCII"); //new Opaque(16, data, 0); + int offset = string_length+2; + + destination_length = Utils.toShort(data, offset); + + offset += 2; + + int length_array = 0; + byte[] curr_data = Utils.cutArray(data, destination_length, offset); + + for (int sum=0; sum"); + + SipRegistration[] sr = new SipRegistration[ds.length]; + + Destination ret = null; + + for(int i=0; i " + dest.getNodeId().print()); + + ret = dest; + + } + } + + } + + else + System.out.println(""); + + } + + return ret; + + } + + private void remove(String aor, NodeId key) throws Exception{ + + ResourceId resource_aor = Module.tpi.hash(aor); + + Opaque[] dictionaryKey = {new Opaque(16, key.getId())}; + + iface.removeDictionary(resource_aor, kind, dictionaryKey); + + } + + private void sipAttach(String aor) throws Exception{ + + Destination dest = fetch(aor); + + if(dest != null){ + + NodeId node = dest.getNodeId(); + + short app = 5060; + + iface.appAttach(node, app); + } + + else + System.out.println("Could not do App Attach."); + + } + + /** + * Initializes the console. This is the last method called. + */ + public void startConsole() throws Exception{ + + boolean exit = false; + + while (!exit){ + + System.out.println("Use \"help\" to show the diffente commands"); + System.out.print(">"); + + Scanner scanner = new Scanner(System.in); + String read = scanner.nextLine(); + + if(read.startsWith("fetch ")){ + String aor = read.substring(6); + fetch(aor); + } + + else if(read.startsWith("remove ")){ + String aor = read.substring(7); + remove(aor, thisNode); + } + + else if(read.startsWith("sip ")){ + String aor = read.substring(4); + sipAttach(aor); + } + + else + if(iface.commonCommand(read)) // If true, exit application + exit = true; + + } + + System.out.println("SIP Exiting..."); + + } + + } \ No newline at end of file diff --git a/reload/Storage/ArrayTable.java b/reload/Storage/ArrayTable.java new file mode 100644 index 0000000..48c52d9 --- /dev/null +++ b/reload/Storage/ArrayTable.java @@ -0,0 +1,565 @@ + + package reload.Storage; + + import reload.Common.*; + import reload.Common.Exception.*; + import reload.Storage.Data.*; + import java.util.*; + +/** + * DictionaryTable class is a table to store array data for the Storage module. + * @author Malosa + * @version 0.1 + */ + public class ArrayTable{ + + private ArrayList kind_id; //indexed + private ArrayList resource_id; // indexed + private ArrayList storage_time; + private ArrayList life_time; + private ArrayList index; //indexed + private ArrayList exists; + private ArrayList value; //32-bit + + /** + * Creates a new empty table. + */ + public ArrayTable(){ + + kind_id = new ArrayList(); + resource_id = new ArrayList(); + storage_time = new ArrayList(); + life_time = new ArrayList(); + index = new ArrayList(); + exists = new ArrayList(); + value = new ArrayList(); + + } + + /** + * Adds a new row in the table. + * @param kid the Kind-ID + * @param rid the Resource-ID + * @param storage_time the storage time + * @param life_time the life time + * @param index the index of the array + * @param exists if value exists (false if it was deleted) + * @param value the value to store + */ + public synchronized void add(KindId kid, ResourceId rid, long storage_time, int life_time, int index, boolean exists, byte[] value) throws ReloadException{ + + if (index == (int)0xffffffff) + index = getArrayLength(kid, rid); + + delete(kid, rid, index); // If exists, deletes old value, if not nothing happens + + this.kind_id.add(kid.getId()); + this.resource_id.add(rid); + this.storage_time.add(storage_time); + this.life_time.add(life_time); + this.index.add(index); + this.exists.add(exists); + this.value.add(new Opaque(32, value)); + + } + + /** + * Adds a new file in the table. + * @param kid the Kind-ID + * @param rid the Resource-ID + * @param storage_time the storage time + * @param life_time the life time + * @param index the index of the array + * @param data_value the DataValue to store + */ + public synchronized void add(KindId kid, ResourceId rid, long storage_time, int life_time, int index, DataValue data_value) throws ReloadException{ + + add(kid, rid, storage_time, life_time, index, data_value.getExists(), data_value.getValue()); + + } + + /** + * Returns some rows from the table. + * @param kid the Kind-ID + * @param rid the Resource-ID + * @return a DataStructure array containing the rows (each DataStructure object is a row) + */ + public DataStructure[] getData(KindId kid, ResourceId rid) throws ReloadException{ + + int max = getArrayLength(kid, rid); + + if(max == -1) + return new DataStructure[0]; + + int size = max+1; + + DataStructure[] ds = new DataStructure[size]; + + long[] s = getInternalStorageTime(kid, rid, size); + int[] l = getInternalLifeTime(kid, rid, size); + boolean[] e = getInternalExists(kid, rid, size); + Opaque[] v = getInternalValue(kid, rid, size); + + for(int i=0; imax) + max = ind; + } + + } + + return max; + + } + + /** + * Returns the storage times of stored values. + * @param kid the Kind-ID + * @param rid the Resource-ID + * @return a storage time array + */ + public long[] getStorageTime(KindId kid, ResourceId rid) throws ReloadException{ + + int max = getArrayLength(kid, rid); + + if(max == -1) + return new long[0]; + + return getInternalStorageTime(kid, rid, max+1); + + } + + private long[] getInternalStorageTime(KindId kid, ResourceId rid, int size) throws ReloadException{ + + + long[] time = new long[size]; + + + for(int index=0, pos=0; true; index=pos+1){ + + pos = resourceIndexOf(rid, index); + + if(pos == -1) + break; + + if(kind_id.get(pos).intValue() == kid.getId()){ + + long st = storage_time.get(pos); + int ind = this.index.get(pos); + + time[ind] = st; + } + + } + + return time; + + } + + /** + * Returns the storage time of a stored value. + * @param kid the Kind-ID + * @param rid the Resource-ID + * @param index the index of the value + * @return the storage time + */ + public long getStorageTime(KindId kid, ResourceId rid, int index) throws ReloadException{ + + return getStorageTime(kid, rid)[index]; + + } + + /** + * Returns the life time of stored values. + * @param kid the Kind-ID + * @param rid the Resource-ID + * @return a life time array + */ + public int[] getLifeTime(KindId kid, ResourceId rid) throws ReloadException{ + + int max = getArrayLength(kid, rid); + + if(max == -1) + return new int[0]; + + return getInternalLifeTime(kid, rid, max+1); + + } + + private int[] getInternalLifeTime(KindId kid, ResourceId rid, int size) throws ReloadException{ + + + int[] time = new int[size]; + + + for(int index=0, pos=0; true; index=pos+1){ + + pos = resourceIndexOf(rid, index); + + if(pos == -1) + break; + + if(kind_id.get(pos).intValue() == kid.getId()){ + + int lt = life_time.get(pos); + int ind = this.index.get(pos); + + time[ind] = lt; + } + + } + + return time; + + } + + /** + * Returns the life time of a stored value. + * @param kid the Kind-ID + * @param rid the Resource-ID + * @param index the index of the value + * @return the life time + */ + public int getLifeTime(KindId kid, ResourceId rid, int index) throws ReloadException{ + + return getLifeTime(kid, rid)[index]; + + } + + /** + * Returns if stored values exist. + * @param kid the Kind-ID + * @param rid the Resource-ID + * @return true if each vale exists, false if not + */ + public boolean[] getExists(KindId kid, ResourceId rid) throws ReloadException{ + + int max = getArrayLength(kid, rid); + + if(max == -1) + return new boolean[0]; + + return getInternalExists(kid, rid, max+1); + + } + + private boolean[] getInternalExists(KindId kid, ResourceId rid, int size) throws ReloadException{ + + + boolean[] exis = new boolean[size]; + + + for(int index=0, pos=0; true; index=pos+1){ + + pos = resourceIndexOf(rid, index); + + if(pos == -1) + break; + + if(kind_id.get(pos).intValue() == kid.getId()){ + + boolean ex = exists.get(pos); + int ind = this.index.get(pos); + + exis[ind] = ex; + } + + } + + return exis; + + } + + /** + * Returns if a stored value exists. + * @param kid the Kind-ID + * @param rid the Resource-ID + * @param index the index of the value + * @return true if exists, false if not + */ + public boolean getExists(KindId kid, ResourceId rid, int index) throws ReloadException{ + + return getExists(kid, rid)[index]; + + } + + /** + * Returns stored values. + * @param kid the Kind-ID + * @param rid the Resource-ID + * @return the stored values in an Opaque array + */ + public Opaque[] getValue(KindId kid, ResourceId rid) throws ReloadException{ + + int max = getArrayLength(kid, rid); + + if(max == -1) + return new Opaque[0]; + + return getInternalValue(kid, rid, max+1); + + } + + private Opaque[] getInternalValue(KindId kid, ResourceId rid, int size) throws ReloadException{ + + + Opaque[] val = new Opaque[size]; + + + for(int index=0, pos=0; true; index=pos+1){ + + pos = resourceIndexOf(rid, index); + + if(pos == -1) + break; + + if(kind_id.get(pos).intValue() == kid.getId()){ + + Opaque opaque = value.get(pos); + int ind = this.index.get(pos); + + val[ind] = opaque; + + } + + } + + return val; + + } + + /** + * Returns a stored value. + * @param kid the Kind-ID + * @param rid the Resource-ID + * @param index the index of the value + * @return the stored value in an Opaque object + */ + public Opaque getValue(KindId kid, ResourceId rid, int index) throws ReloadException{ + + return getValue(kid, rid)[index]; + + } + + /** + * Deletes a row from the table. + * @param kid the Kind-ID + * @param rid the Resource-ID + * @param index the index of the array + * @return true if could be deleted + */ + public synchronized boolean delete(KindId kid, ResourceId rid, int index) throws ReloadException{ + + for(int ind=0, pos=0; true; ind=pos+1){ + + pos = resourceIndexOf(rid, ind); + + if(pos == -1) + return false; + + if(kind_id.get(pos).intValue() == kid.getId() && this.index.get(pos) == index){ + + remove(pos); + break; + } + + } + + if(!contains(kid, rid)){ + Module.si.resource_kind.delete(kid, rid); + + if(!Module.si.resource_kind.contains(rid)) + Module.si.resource_rep.delete(rid); + } + + return true; + + } + + /** + * Deletes some rows from the table. + * @param kid the Kind-ID + * @param rid the Resource-ID + */ + public synchronized void delete(KindId kid, ResourceId rid) throws ReloadException{ + + for(int ind=0, pos=0; true; ind=pos+1){ + + pos = resourceIndexOf(rid, ind); + + if(pos == -1) + break; + + if(kind_id.get(pos).intValue() == kid.getId()) + remove(pos--); + } + + Module.si.resource_kind.delete(kid, rid); + + if(!Module.si.resource_kind.contains(rid)) + Module.si.resource_rep.delete(rid); + + } + + /** + * Deletes some rows from the table. + * @param rid the Resource-ID + */ + public synchronized void delete(ResourceId rid) throws ReloadException{ + + for(int ind=0, pos=0; true; ind=pos+1){ + + pos = resourceIndexOf(rid, ind); + + if(pos == -1) + break; + + else + remove(pos--); + + } + + Module.si.resource_kind.delete(rid); + + Module.si.resource_rep.delete(rid); + + } + + private void remove(int pos){ + + kind_id.remove(pos); + storage_time.remove(pos); + life_time.remove(pos); + index.remove(pos); + exists.remove(pos); + value.remove(pos); + + } + + /** + * Returns if the table contains the specified element. + * @param kid the Kind-ID + * @param rid the Resource-ID + * @return true if contains, false if not + */ + public boolean contains(KindId kid, ResourceId rid) throws ReloadException{ + + for(int ind=0, pos=0; true; ind=pos+1){ + + pos = resourceIndexOf(rid, ind); + + if(pos == -1) + return false; + + if(kind_id.get(pos).intValue() == kid.getId()) + return true; + + } + + } + + /** + * Returns if the table contains the specified element. + * @param rid the Resource-ID + * @return true if contains, false if not + */ + public boolean contains(ResourceId rid) throws ReloadException{ + + if(resourceIndexOf(rid, 0) == -1) + return false; + + else + return true; + + } + + /** + * Returns the index of the first occurrence of the specified Resource-ID in the table, searching forwards from pos, or returns -1 if the element is not found. + * @param o the Resource-ID + * @param pos the index to start searching from + * @return the index + */ + public int resourceIndexOf(ResourceId o, int pos) throws ReloadException{ + + ListIterator it; + + try{ + it = resource_id.listIterator(pos); + } + catch(IndexOutOfBoundsException ioobe){ + return -1; + } + + for(int i=0; it.hasNext(); i++){ + + ResourceId current = (ResourceId)it.next(); + + if(current.equals(o)) + return pos+i; + + } + + return -1; + + } + + } \ No newline at end of file diff --git a/reload/Storage/Data/ArrayEntry.java b/reload/Storage/Data/ArrayEntry.java new file mode 100644 index 0000000..3dc0236 --- /dev/null +++ b/reload/Storage/Data/ArrayEntry.java @@ -0,0 +1,52 @@ + package reload.Storage.Data; + + import java.io.*; + import reload.Common.*; + import reload.Common.Exception.*; + + public class ArrayEntry{ + + + private int index; + private DataValue value; + + + + public ArrayEntry (int index, DataValue value){ + + this.index = index; + this.value = value; + + } + + public ArrayEntry (byte[] data) throws ReloadException{ + + index = Utils.toInt(data, 0); + value = new DataValue(Utils.cutArray(data, 4)); + + } + + public byte[] getBytes() throws IOException{ + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + baos.write(Utils.toByte(index)); + baos.write(value.getBytes()); + + return baos.toByteArray(); + + } + + public int getIndex(){ + + return index; + + } + + public DataValue getDataValue(){ + + return value; + + } + + } \ No newline at end of file diff --git a/reload/Storage/Data/ArrayEntryMeta.java b/reload/Storage/Data/ArrayEntryMeta.java new file mode 100644 index 0000000..91967d6 --- /dev/null +++ b/reload/Storage/Data/ArrayEntryMeta.java @@ -0,0 +1,52 @@ + package reload.Storage.Data; + + import java.io.*; + import reload.Common.*; + import reload.Common.Exception.*; + + public class ArrayEntryMeta{ + + + private int index; + private MetaData value; + + + + public ArrayEntryMeta (int index, MetaData value){ + + this.index = index; + this.value = value; + + } + + public ArrayEntryMeta (byte[] data) throws ReloadException{ + + index = Utils.toInt(data, 0); + value = new MetaData(Utils.cutArray(data, 4)); + + } + + public byte[] getBytes() throws IOException{ + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + baos.write(Utils.toByte(index)); + baos.write(value.getBytes()); + + return baos.toByteArray(); + + } + + public int getIndex(){ + + return index; + + } + + public MetaData getValue(){ + + return value; + + } + + } \ No newline at end of file diff --git a/reload/Storage/Data/ArrayRange.java b/reload/Storage/Data/ArrayRange.java new file mode 100644 index 0000000..ea56714 --- /dev/null +++ b/reload/Storage/Data/ArrayRange.java @@ -0,0 +1,51 @@ + package reload.Storage.Data; + + import java.io.*; + import reload.Common.*; + + + public class ArrayRange{ + + + private int first; + private int last; + + + public ArrayRange (int first, int last){ + + this.first = first; + this.last = last; + + } + + public ArrayRange (byte[] data) { + + first = Utils.toInt(data, 0); + last = Utils.toInt(data, 4); + + } + + public byte[] getBytes() throws IOException{ + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + baos.write(Utils.toByte(first)); + baos.write(Utils.toByte(last)); + + return baos.toByteArray(); + + } + + public int getFirst(){ + + return first; + + } + + public int getLast(){ + + return last; + + } + + } \ No newline at end of file diff --git a/reload/Storage/Data/DataValue.java b/reload/Storage/Data/DataValue.java new file mode 100644 index 0000000..a89f731 --- /dev/null +++ b/reload/Storage/Data/DataValue.java @@ -0,0 +1,66 @@ + package reload.Storage.Data; + + import java.io.*; + import reload.Common.*; + import reload.Common.Exception.*; + + public class DataValue{ + + private boolean exists; + private Opaque value; //32-bit + + + public DataValue (boolean exists, byte[] value) throws ReloadException{ + + this.exists = exists; + this.value = new Opaque(32, value); + + } + + public DataValue (boolean exists, Opaque value) throws ReloadException{ + + this.exists = exists; + this.value = value; + + if(value.getBits() != 32) + throw new WrongLengthReloadException(); + + } + + public DataValue (byte[] data) throws ReloadException{ + + exists = Utils.toBoolean(data[0]); + value = new Opaque(32, data, 1); + + } + + public byte[] getBytes() throws IOException{ + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + baos.write(Utils.toByte(exists)); + baos.write(value.getBytes()); + + return baos.toByteArray(); + + } + + public boolean getExists(){ + + return exists; + + } + + public byte[] getValue(){ + + return value.getContent(); + + } + + public Opaque getOpaqueValue(){ + + return value; + + } + + } \ No newline at end of file diff --git a/reload/Storage/Data/DictionaryEntry.java b/reload/Storage/Data/DictionaryEntry.java new file mode 100644 index 0000000..b5cc9a6 --- /dev/null +++ b/reload/Storage/Data/DictionaryEntry.java @@ -0,0 +1,52 @@ + package reload.Storage.Data; + + import java.io.*; + import reload.Common.*; + + public class DictionaryEntry{ + + + private DictionaryKey key; + private DataValue value; + + + + public DictionaryEntry (DictionaryKey key, DataValue value){ + + this.key = key; + this.value = value; + + } + + public DictionaryEntry (byte[] data) throws Exception{ + + key = new DictionaryKey(data, false); + int length = key.getBytes().length; + value = new DataValue(Utils.cutArray(data, length)); + + } + + public byte[] getBytes() throws IOException{ + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + baos.write(key.getBytes()); + baos.write(value.getBytes()); + + return baos.toByteArray(); + + } + + public DictionaryKey getDictionaryKey(){ + + return key; + + } + + public DataValue getDataValue(){ + + return value; + + } + + } \ No newline at end of file diff --git a/reload/Storage/Data/DictionaryEntryMeta.java b/reload/Storage/Data/DictionaryEntryMeta.java new file mode 100644 index 0000000..a4a5c0d --- /dev/null +++ b/reload/Storage/Data/DictionaryEntryMeta.java @@ -0,0 +1,53 @@ + package reload.Storage.Data; + + import java.io.*; + import reload.Common.*; + + + public class DictionaryEntryMeta{ + + + private DictionaryKey key; + private MetaData value; + + + + public DictionaryEntryMeta (DictionaryKey key, MetaData value){ + + this.key = key; + this.value = value; + + } + + public DictionaryEntryMeta (byte[] data) throws Exception{ + + key = new DictionaryKey(data, false); + int length = key.getBytes().length; + value = new MetaData(Utils.cutArray(data, length)); + + } + + public byte[] getBytes() throws IOException{ + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + baos.write(key.getBytes()); + baos.write(value.getBytes()); + + return baos.toByteArray(); + + } + + public DictionaryKey getKey(){ + + return key; + + } + + public MetaData getValue(){ + + return value; + + } + + } \ No newline at end of file diff --git a/reload/Storage/Data/DictionaryKey.java b/reload/Storage/Data/DictionaryKey.java new file mode 100644 index 0000000..573b06f --- /dev/null +++ b/reload/Storage/Data/DictionaryKey.java @@ -0,0 +1,42 @@ + package reload.Storage.Data; + + import java.io.*; + import reload.Common.*; + import reload.Common.Exception.*; + + public class DictionaryKey{ + + private Opaque id; // 16-bit + + public DictionaryKey(byte[] data, boolean upper) throws ReloadException{ // Upper and lower levels + + if(upper) + id = new Opaque(16, data); + + else + id = new Opaque(16, data, 0); + + } + + public DictionaryKey(Opaque data) throws ReloadException{ // Upper level + + id = data; + + if(data.getBits() != 16) + throw new WrongLengthReloadException(); + + } + + public byte[] getBytes() throws IOException{ + + return id.getBytes(); + + } + + public byte[] getKey(){ + + return id.getContent(); + + } + + } \ No newline at end of file diff --git a/reload/Storage/Data/FetchAns.java b/reload/Storage/Data/FetchAns.java new file mode 100644 index 0000000..dc973aa --- /dev/null +++ b/reload/Storage/Data/FetchAns.java @@ -0,0 +1,64 @@ + package reload.Storage.Data; + + import java.io.*; + import reload.Common.*; + import reload.Common.Exception.*; + + public class FetchAns{ + + private int kind_length; + private FetchKindResponse[] kind_responses; //<0..2^32-1> + + + public FetchAns (FetchKindResponse[] kind_responses) throws Exception{ + + this.kind_responses = kind_responses; + + for (int i=0; i Math.pow(2, 32)-1) + throw new WrongLengthReloadException(); + + } + + public FetchAns (byte[] data) throws Exception{ + + + kind_length = Utils.toInt(data, 0); + + data = Utils.cutArray(data, kind_length, 4); + int offset = 0; + + int num = Algorithm.counter(4, data, 12); + + kind_responses = new FetchKindResponse[num]; + + for (int i=0; i + + + public FetchKindResponse (KindId kind, long generation, StoredData[] values) throws Exception{ + + this.kind = kind; + this.generation = generation; + this.values = values; + + for (int i=0; i Math.pow(2, 32)-1) + throw new WrongLengthReloadException(); + + } + + public FetchKindResponse (byte[] data) throws Exception{ + + kind = new KindId(data); // 32-bit + generation = Utils.toLong(data, 4); + values_length = Utils.toInt(data, 12); + + data = Utils.cutArray(data, values_length, 16); + int offset = 0; + + int num = Algorithm.counter(4, data, 0); + + values = new StoredData[num]; + + DataModel dataModel = kind.getDataModel(); + + for (int i=0; i + + + public FetchReq (ResourceId resource, StoredDataSpecifier[] specifiers) throws Exception{ + + this.resource = resource; + this.specifiers = specifiers; + + for (int i=0; i Math.pow(2, 16)-1) + throw new WrongLengthReloadException(); + + } + + public FetchReq (byte[] data) throws Exception{ + + resource = new ResourceId(data, false); // Lower level + + int offset = resource.getBytes().length; + + specifiers_length = Utils.toShort(data, offset); + + data = Utils.cutArray(data, specifiers_length, offset + 2); + offset = 0; + + int num = Algorithm.counter(2, data, 12); + + specifiers = new StoredDataSpecifier[num]; + + for (int i=0; i + + + public FindAns (FindKindData[] results) throws Exception{ + + this.results = results; + + for (int i=0; i Math.pow(2, 16)-1) + throw new WrongLengthReloadException(); + + } + + public FindAns (byte[] data) throws Exception{ + + + results_length = Utils.toShort(data, 0); + + data = Utils.cutArray(data, results_length, 2); + int offset = 0; + + int num = Algorithm.counter(1, data, 4); + + results = new FindKindData[num]; + + for (int i=0; i + + + public FindReq (ResourceId resource, byte replica_number, KindId[] kinds) throws Exception{ + + this.resource = resource; + this.kinds = kinds; + + for (int i=0; i Math.pow(2, 8)-1) + throw new WrongLengthReloadException(); + + } + + public FindReq (byte[] data) throws Exception{ + + resource = new ResourceId(data, false); //Lower levers + int offset = resource.getBytes().length; + + kinds_length = data[offset]; + offset++; + + data = Utils.cutArray(data, kinds_length, offset); + offset = 0; + + if (data.length % 4 != 0) + throw new WrongLengthReloadException(); + + int num = data.length / 4; + + kinds = new KindId[num]; + + for (int i=0; i + + public MetaData (boolean exists, HashAlgorithm hash_algorithm, byte[] hash_value) throws ReloadException{ + + this.exists = exists; + this.hash_algorithm = hash_algorithm; + this.hash_value = new Opaque(8, hash_value); + + value_length = hash_value.length + 1; + + } + + public MetaData (byte[] data) throws ReloadException{ + + exists = Utils.toBoolean(data[0]); + value_length = Utils.toInt(data, 1); + hash_algorithm = HashAlgorithm.valueOf(data[5]); + hash_value = new Opaque(8, data, 6); + + } + + public byte[] getBytes() throws IOException{ + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + baos.write(Utils.toByte(exists)); + baos.write(Utils.toByte(value_length)); + baos.write(hash_algorithm.getBytes()); + baos.write(hash_value.getBytes()); + + return baos.toByteArray(); + + } + + public boolean getExists(){ + + return exists; + + } + + public HashAlgorithm getHashAlgorithm(){ + + return hash_algorithm; + + } + + public byte[] getHashValue(){ + + return hash_value.getContent(); + + } + + } \ No newline at end of file diff --git a/reload/Storage/Data/MetaDataValue.java b/reload/Storage/Data/MetaDataValue.java new file mode 100644 index 0000000..6fccbbf --- /dev/null +++ b/reload/Storage/Data/MetaDataValue.java @@ -0,0 +1,113 @@ + package reload.Storage.Data; + + import java.io.*; + import java.util.ArrayList; + import reload.Common.*; + import reload.Common.Exception.*; + import reload.Storage.Data.*; + + public class MetaDataValue{ + + + private DataModel dataModel; + + private MetaData single_value_entry; + + private ArrayEntryMeta array_entry; + + private DictionaryEntryMeta dictionary_entry; + + + public MetaDataValue (MetaData single_value_entry){ + + + dataModel = DataModel.single_value; + + this.single_value_entry = single_value_entry; + + } + + public MetaDataValue (ArrayEntryMeta array_entry){ + + dataModel = DataModel.array; + + this.array_entry=array_entry; + + } + + public MetaDataValue (DictionaryEntryMeta dictionary_entry){ + + dataModel = DataModel.dictionary; + + this.dictionary_entry = dictionary_entry; + + } + + public MetaDataValue (byte[] data, DataModel dataModel) throws Exception{ + + + switch(dataModel.getBytes()){ + case 1: + single_value_entry = new MetaData(data); + break; + case 2: + array_entry = new ArrayEntryMeta(data); + break; + case 3: + dictionary_entry = new DictionaryEntryMeta(data); + break; + default: + throw new WrongTypeReloadException(); + } + + } + + public byte[] getBytes() throws Exception{ + + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + switch(dataModel.getBytes()){ + + case 1: + baos.write(single_value_entry.getBytes()); + break; + case 2: + baos.write(array_entry.getBytes()); + break; + case 3: + baos.write(dictionary_entry.getBytes()); + break; + default: + throw new WrongTypeReloadException(); + } + + return baos.toByteArray(); + + } + + public DataModel getDataModel(){ + + return dataModel; + + } + + public MetaData getSingleValueEntry(){ + + return single_value_entry; + + } + + public ArrayEntryMeta getArrayEntry(){ + + return array_entry; + + } + + public DictionaryEntryMeta getDictionaryEntry(){ + + return dictionary_entry; + + } + + } \ No newline at end of file diff --git a/reload/Storage/Data/StatAns.java b/reload/Storage/Data/StatAns.java new file mode 100644 index 0000000..68ebddc --- /dev/null +++ b/reload/Storage/Data/StatAns.java @@ -0,0 +1,65 @@ + package reload.Storage.Data; + + import java.io.*; + import reload.Common.*; + import reload.Common.Exception.*; + + public class StatAns{ + + + private int kind_length; + private StatKindResponse[] kind_responses; //<0..2^32-1> + + + public StatAns (StatKindResponse[] kind_responses) throws Exception{ + + this.kind_responses = kind_responses; + + for (int i=0; i Math.pow(2, 32)-1) + throw new WrongLengthReloadException(); + + } + + public StatAns (byte[] data) throws Exception{ + + + kind_length = Utils.toInt(data, 0); + + data = Utils.cutArray(data, kind_length, 4); + int offset = 0; + + int num = Algorithm.counter(4, data, 12); + + kind_responses = new StatKindResponse[num]; + + for (int i=0; i + + + public StatKindResponse (KindId kind, long generation, StoredMetaData[] values) throws Exception{ + + this.kind = kind; + this.generation = generation; + this.values = values; + + for (int i=0; i Math.pow(2, 32)-1) + throw new WrongLengthReloadException(); + + } + + public StatKindResponse (byte[] data) throws Exception{ + + kind = new KindId(data); // 32-bit + generation = Utils.toLong(data, 4); + + values_length = Utils.toInt(data, 12); + + data = Utils.cutArray(data, values_length, 16); + int offset = 0; + + int num = Algorithm.counter(4, data, 0); + + values = new StoredMetaData[num]; + + DataModel dataModel = kind.getDataModel(); + + for (int i=0; i + + + public StatReq (ResourceId resource, StoredDataSpecifier[] specifiers) throws Exception{ + + this.resource = resource; + this.specifiers = specifiers; + + for (int i=0; i Math.pow(2, 16)-1) + throw new WrongLengthReloadException(); + + } + + public StatReq (byte[] data) throws Exception{ + + + resource = new ResourceId(data, false); // Lower levels + int offset = resource.getBytes().length; + + specifiers_length = Utils.toShort(data, offset); + offset += 2; + + data = Utils.cutArray(data, specifiers_length, offset); + offset = 0; + + int num = Algorithm.counter(2, data, 12); + + specifiers = new StoredDataSpecifier[num]; + + for (int i=0; i + + + public StoreAns (StoreKindResponse[] kind_responses) throws Exception{ + + this.kind_responses = kind_responses; + + for (int i=0; i Math.pow(2, 16)-1) + throw new WrongLengthReloadException(); + + } + + public StoreAns (byte[] data) throws Exception{ + + kind_length = Utils.toShort(data, 0); + + data = Utils.cutArray(data, kind_length, 2); + + int offset = 0; + + int num = Algorithm.counter(2, data, 12); + + kind_responses = new StoreKindResponse[num]; + + for (int i=0; i + + + public StoreKindData (KindId kind, long generation_counter, StoredData[] values) throws Exception{ + + this.kind = kind; + this.generation_counter = generation_counter; + this.values = values; + + for (int i=0; i Math.pow(2, 32)-1) + throw new WrongLengthReloadException(); + + } + + public StoreKindData (byte[] data) throws Exception{ + + kind = new KindId(data); // 32-bit + generation_counter = Utils.toLong(data, 4); + + values_length = Utils.toInt(data, 12); + + data = Utils.cutArray(data, values_length, 16); + int offset = 0; + + int num = Algorithm.counter(4, data, 0); + + values = new StoredData[num]; + + DataModel dataModel = kind.getDataModel(); + + for (int i=0; i + + + public StoreKindResponse (KindId kind, long generation_counter, NodeId[] replicas) throws Exception{ + + this.kind = kind; + this.generation_counter = generation_counter; + this.replicas = replicas; + + for (int i=0; i Math.pow(2, 16)-1) + throw new WrongLengthReloadException(); + + } + + public StoreKindResponse (byte[] data) throws Exception{ + + kind = new KindId(data); // 32-bit + generation_counter = Utils.toLong(data, 4); + replicas_length = Utils.toShort(data, 12); + + data = Utils.cutArray(data, replicas_length, 14); + + if (data.length % NodeId.getLength() != 0) + throw new WrongLengthReloadException(); + + int num = data.length / NodeId.getLength(); + + int offset=0; + + replicas = new NodeId[num]; + + for (int i=0; i + + + public StoreReq (ResourceId resource, byte replica_number, StoreKindData[] kind_data) throws Exception{ + + this.resource = resource; + this.replica_number = replica_number; + this.kind_data = kind_data; + + for (int i=0; i Math.pow(2, 32)-1) + throw new WrongLengthReloadException(); + + } + + public StoreReq (byte[] data) throws Exception{ + + resource = new ResourceId(data, false); // Lower level + int offset = resource.getBytes().length; + + replica_number = data[offset]; + offset++; + + kind_length = Utils.toInt(data, offset); + offset += 4; + + data = Utils.cutArray(data, kind_length, offset); + offset = 0; + + int num = Algorithm.counter(4, data, 12); + + kind_data = new StoreKindData[num]; + + for (int i=0; i + + private DictionaryKey[] keys; //<0..2^16-1> + + + public StoredDataSpecifier (KindId kind, long generation){ + + this.kind = kind; + this.generation = generation; + length = 0; + + dataModel = DataModel.single_value; + + } + + public StoredDataSpecifier (KindId kind, long generation, ArrayRange[] indices) throws ReloadException{ + + this(kind, generation); + + dataModel = DataModel.array; + + this.indices=indices; + + length = (short)(8*indices.length); + + if(length > Math.pow(2, 16)-1) + throw new WrongLengthReloadException(); + + } + + public StoredDataSpecifier (KindId kind, long generation, DictionaryKey[] keys) throws Exception{ + + this(kind, generation); + + dataModel = DataModel.dictionary; + + this.keys = keys; + + for (int i=0; i Math.pow(2, 16)-1) + throw new WrongLengthReloadException(); + + } + + public StoredDataSpecifier (byte[] data) throws Exception{ + + kind = new KindId(data); // 32-bit + generation = Utils.toLong(data, 4); + + length = Utils.toShort(data, 12); + + dataModel = kind.getDataModel(); + + data = Utils.cutArray(data, length, 14); + int offset=0; + + switch(dataModel.getBytes()){ + + case 2: + + if (length % 8 != 0) + throw new WrongLengthReloadException(); + + int num = length/8; + indices = new ArrayRange[num]; + + for (int i=0; i kind_id; //indexed + private ArrayList resource_id; // indexed + private ArrayList storage_time; + private ArrayList life_time; + private ArrayList dictionary_key; //indexed + private ArrayList exists; + private ArrayList value; //32-bit + + /** + * Creates a new empty table. + */ + public DictionaryTable(){ + + kind_id = new ArrayList(); + resource_id = new ArrayList(); + storage_time = new ArrayList(); + life_time = new ArrayList(); + dictionary_key = new ArrayList(); + exists = new ArrayList(); + value = new ArrayList(); + + } + + /** + * Adds a new row in the table. + * @param kid the Kind-ID + * @param rid the Resource-ID + * @param storage_time the storage time + * @param life_time the life time + * @param key the dictionary key + * @param exists if value exists (false if it was deleted) + * @param value the value to store + */ + public synchronized void add(KindId kid, ResourceId rid, long storage_time, int life_time, DictionaryKey key, boolean exists, byte[] value) throws ReloadException{ + + delete(kid, rid, key); // If exists, deletes old value, if not, nothing happens + + Module.si.resource_kind.add(rid, kid); + + this.kind_id.add(kid.getId()); + this.resource_id.add(rid); + this.storage_time.add(storage_time); + this.life_time.add(life_time); + dictionary_key.add(key.getKey()); + this.exists.add(exists); + this.value.add(new Opaque(32, value)); + + } + + /** + * Adds a new file in the table. + * @param kid the Kind-ID + * @param rid the Resource-ID + * @param storage_time the storage time + * @param life_time the life time + * @param key the dictionary key + * @param data_value the DataValue to store + */ + public synchronized void add(KindId kid, ResourceId rid, long storage_time, int life_time, DictionaryKey key, DataValue data_value) throws ReloadException{ + + add(kid, rid, storage_time, life_time, key, data_value.getExists(), data_value.getValue()); + + } + + /** + * Returns some rows from the table. + * @param kid the Kind-ID + * @param rid the Resource-ID + * @return a DataStructure array containing the rows (each DataStructure object is a row) + */ + public DataStructure[] getData(KindId kid, ResourceId rid) throws ReloadException{ + + + int[] position = getPositions(kid, rid); + + if(position.length == 0) + return new DataStructure[0]; + + DataStructure[] ds = new DataStructure[position.length]; + + DictionaryKey[] d = getInternalDictionaryKey(position); + long[] s = getInternalStorageTime(position); + int[] l = getInternalLifeTime(position); + boolean[] e = getInternalExists(position); + Opaque[] v = getInternalValue(position); + + + for(int i=0; i ret = new ArrayList(); + + for(int i=0; i position = new ArrayList(); + + for(int index=0, pos=0; true; index=pos+1){ + + pos = resourceIndexOf(rid, index); + + if(pos == -1) + break; + + if(kind_id.get(pos).intValue() == kid.getId()) + position.add(pos); + + } + + return toArray(position); + + } + + /** + * Returns the storage times of stored values. + * @param kid the Kind-ID + * @param rid the Resource-ID + * @return a storage time array + */ + public long[] getStorageTime(KindId kid, ResourceId rid) throws ReloadException{ + + int[] position = getPositions(kid, rid); + + if(position.length == 0) + return new long[0]; + + return getInternalStorageTime(position); + + } + + private long[] getInternalStorageTime(int[] position){ + + long[] time = new long[position.length]; + + for(int i=0; i list) { + + Integer[] inte = list.toArray(new Integer[0]); + + int[] ret = new int[inte.length]; + + for (int i=0; i kind_id; + ArrayList resource_id; + ArrayList gen_counter; + + + public KindCounterList(){ + + kind_id = new ArrayList(); + resource_id = new ArrayList(); + gen_counter = new ArrayList(); + + } + + public synchronized void add(KindId kid, ResourceId rid, long gen_counter) throws ReloadException{ + + delete(kid, rid); // If exists, deletes old value, if not nothing happens + + kind_id.add(kid.getId()); + resource_id.add(rid); + this.gen_counter.add(gen_counter); + + } + + public long getGenerationCounter(KindId kid, ResourceId rid) throws ReloadException{ + + for(int index=0, pos=0; true; index=pos+1){ + + pos = resourceIndexOf(rid, index); + + if(pos == -1) + return -1; + + if(kind_id.get(pos).intValue() == kid.getId()) + return gen_counter.get(pos); + + } + + } + + public boolean contains(KindId kid, ResourceId rid) throws ReloadException{ + + for(int ind=0, pos=0; true; ind=pos+1){ + + pos = resourceIndexOf(rid, ind); + + if(pos == -1) + return false; + + if(kind_id.get(pos).intValue() == kid.getId()) + return true; + + } + + } + + public synchronized boolean delete(KindId kid, ResourceId rid) throws ReloadException{ + + for(int ind=0, pos=0; true; ind=pos+1){ + + pos = resourceIndexOf(rid, ind); + + if(pos == -1) + return false; + + if(kind_id.get(pos).intValue() == kid.getId()){ + kind_id.remove(pos); + resource_id.remove(pos); + gen_counter.remove(pos); + return true; + } + + } + + + + } + + public int resourceIndexOf(ResourceId o, int pos) throws ReloadException{ + + ListIterator it; + + try{ + it = resource_id.listIterator(pos); + } + catch(IndexOutOfBoundsException ioobe){ + return -1; + } + + for(int i=0; it.hasNext(); i++){ + + ResourceId current = (ResourceId)it.next(); + + if(current.equals(o)) + return pos+i; + + } + + return -1; + + } + + } \ No newline at end of file diff --git a/reload/Storage/KindModelList.java b/reload/Storage/KindModelList.java new file mode 100644 index 0000000..991ca1d --- /dev/null +++ b/reload/Storage/KindModelList.java @@ -0,0 +1,149 @@ + + package reload.Storage; + + import reload.Common.*; + import reload.Common.Exception.*; + import java.util.*; + + public class KindModelList{ + + ArrayList kind_id; + ArrayList name; + ArrayList dataModel; + + DataModel commonDM; + boolean common; + + // If common = two columns + // If !common = three columns + + + public KindModelList(){ + + kind_id = new ArrayList(); + name = new ArrayList(); + dataModel = new ArrayList(); + + common = false; + + } + + public KindModelList(DataModel commonDM){ + + kind_id = new ArrayList(); + name = new ArrayList(); + + this.commonDM = commonDM; + common = true; + + } + + public synchronized void add(KindId id, String name, DataModel dataModel) throws ReloadException{ + + delete(id); + + kind_id.add(id.getId()); + this.name.add(name); + + if (common){ + + if(dataModel != commonDM) + throw new WrongTypeReloadException(); + } + + else + this.dataModel.add(dataModel); + + } + + public synchronized void add(KindId id, String name) throws ReloadException{ + + delete(id); + + kind_id.add(id.getId()); + this.name.add(name); + + if(!common) + throw new WrongTypeReloadException(); + + } + + public DataModel getDataModel(int kid){ // Call from KindId + + if(common) + return commonDM; + + + int pos = kind_id.indexOf(kid); + + if(pos == -1) + return DataModel.UNDEFINED; + + else + return dataModel.get(pos); + + } + + public DataModel getDataModel(KindId kid){ + + return getDataModel(kid.getId()); + + } + + public boolean isCommon(){ + + return common; + + } + + public DataModel getDataModel() throws ReloadException{ + + if (!common) + throw new ReloadException("No KindId specified."); + + return commonDM; + + } + + public String getName(KindId kid){ + + int pos = kind_id.indexOf(kid.getId()); + + if(pos == -1) + return null; + + else + return name.get(pos); + + } + + public boolean contains(KindId kid){ + + int pos = kind_id.indexOf(kid.getId()); + + if(pos == -1) + return false; + + else + return true; + + } + + public synchronized boolean delete(KindId kid){ + + int pos = kind_id.indexOf(kid.getId()); + + if(pos == -1) + return false; + + kind_id.remove(pos); + name.remove(pos); + + if(!common) + dataModel.remove(pos); + + return true; + + } + + } \ No newline at end of file diff --git a/reload/Storage/ResourceKindList.java b/reload/Storage/ResourceKindList.java new file mode 100644 index 0000000..d6d9ea9 --- /dev/null +++ b/reload/Storage/ResourceKindList.java @@ -0,0 +1,149 @@ + + package reload.Storage; + + import reload.Common.*; + import reload.Common.Exception.*; + import java.util.*; + + public class ResourceKindList{ + + private ArrayList resource_id; + private ArrayList data; + + + public ResourceKindList(){ + + resource_id = new ArrayList(); + data = new ArrayList(); + + } + + public synchronized void add(ResourceId rid, KindId kid) throws ReloadException{ + + if(!contains(kid, rid)){ + resource_id.add(rid); + data.add(kid); + } + + } + + public KindId[] getKinds(ResourceId rid) throws ReloadException{ + + ArrayList ret = new ArrayList(); + + for(int index=0, pos=0; true; index=pos+1){ + + pos = resourceIndexOf(rid, index); + + if(pos == -1) + break; + + else + ret.add(data.get(pos)); + + } + + return ret.toArray(new KindId[0]); + + } + + public synchronized void delete(ResourceId rid) throws ReloadException{ + + for(int index=0, pos=0; true; index=pos){ + + pos = resourceIndexOf(rid, index); + + if(pos == -1) + break; + + resource_id.remove(pos); + data.remove(pos); + + } + + } + + public synchronized boolean delete(KindId kid, ResourceId rid) throws ReloadException{ + + for(int index=0, pos=0; true; index=pos+1){ + + pos = resourceIndexOf(rid, index); + + if(pos == -1) + return false; + + if(data.get(pos).getId() == kid.getId()){ + resource_id.remove(pos); + data.remove(pos); + return true; + } + + } + + } + + public boolean contains(KindId kid, ResourceId rid) throws ReloadException{ + + for(int index=0, pos=0; true; index=pos+1){ + + pos = resourceIndexOf(rid, index); + + if(pos == -1) + return false; + + if(data.get(pos).getId() == kid.getId()) + return true; + + } + + } + + public boolean contains(ResourceId rid) throws ReloadException{ + + if(resourceIndexOf(rid, 0) == -1) + return false; + + else + return true; + + } + + public ResourceId[] getResources() throws ReloadException{ + + ArrayList list = new ArrayList(); + + for(int i=0; i resource_id; + private ArrayList replica; + + + public ResourceReplicaList(){ + + resource_id = new ArrayList(); + replica = new ArrayList(); + + } + + public synchronized void add(ResourceId id, byte replica) throws ReloadException{ + + if(contains(id)) + delete(id); + + resource_id.add(id); + this.replica.add(replica); + + } + + public byte getReplica(ResourceId rid) throws ReloadException{ + + int pos = resourceIndexOf(rid); + + if(pos == -1) + return -1; + + else + return replica.get(pos); + + } + + public ResourceId[] getResources() throws ReloadException{ + + return resource_id.toArray(new ResourceId[0]); + + } + + public synchronized boolean delete(ResourceId rid){ + + int pos = resource_id.indexOf(rid.getId()); + + if(pos == -1) + return false; + + resource_id.remove(pos); + replica.remove(pos); + + return true; + + } + + public boolean contains(ResourceId rid) throws ReloadException{ + + if(resourceIndexOf(rid) == -1) + return false; + + else + return true; + + } + + public int resourceIndexOf(ResourceId o) throws ReloadException{ + + int pos = 0; + + ListIterator it; + + try{ + it = resource_id.listIterator(pos); + } + catch(IndexOutOfBoundsException ioobe){ + return -1; + } + + for(int i=0; it.hasNext(); i++){ + + ResourceId current = (ResourceId)it.next(); + + if(current.equals(o)) + return pos+i; + + } + + return -1; + + } + + public String print() throws Exception{ + + String ret = new String(); + int size = resource_id.size(); + + if(size == 0) + ret += ""; + else + ret += "#\tResource-ID\t\t\t\tReplica\n"; + + for(int i=0; i kind_id; + private ArrayList resource_id; + private ArrayList storage_time; + private ArrayList life_time; + private ArrayList exists; + private ArrayList value; //32-bit + + /** + * Creates a new empty table. + */ + public SingleValueTable(){ + + kind_id = new ArrayList(); + resource_id = new ArrayList(); + storage_time = new ArrayList(); + life_time = new ArrayList(); + exists = new ArrayList(); + value = new ArrayList(); + + } + + /** + * Adds a new row in the table. + * @param kid the Kind-ID + * @param rid the Resource-ID + * @param storage_time the storage time + * @param life_time the life time + * @param exists if value exists (false if it was deleted) + * @param value the value to store + */ + public synchronized void add(KindId kid, ResourceId rid, long storage_time, int life_time, boolean exists, byte[] value) throws ReloadException{ + + delete(kid, rid); // If exists, deletes old value, if not nothing happens + + this.kind_id.add(kid.getId()); + this.resource_id.add(rid); + this.storage_time.add(storage_time); + this.life_time.add(life_time); + this.exists.add(exists); + this.value.add(new Opaque(32, value)); + + } + + /** + * Adds a new file in the table. + * @param kid the Kind-ID + * @param rid the Resource-ID + * @param storage_time the storage time + * @param life_time the life time + * @param data_value the DataValue to store + */ + public synchronized void add(KindId kid, ResourceId rid, long storage_time, int life_time, DataValue data_value) throws ReloadException{ + + add(kid, rid, storage_time, life_time, data_value.getExists(), data_value.getValue()); + + } + + /** + * Returns a row from the table. + * @param kid the Kind-ID + * @param rid the Resource-ID + * @return a DataStructure object containing the row + */ + public DataStructure getData(KindId kid, ResourceId rid) throws ReloadException{ + + long s = getStorageTime(kid, rid); + int l = getLifeTime(kid, rid); + boolean e = getExists(kid, rid); + Opaque v = getValue(kid, rid); + + return new DataStructure(s, l, e, v); + + } + + /** + * Returns the storage time of a stored value. + * @param kid the Kind-ID + * @param rid the Resource-ID + * @return the storage time + */ + public long getStorageTime(KindId kid, ResourceId rid) throws ReloadException{ + + int pos = indexOf(kid, rid); + + if(pos == -1) + return -1; + + else + return storage_time.get(pos); + + } + + /** + * Returns the life time of a stored value. + * @param kid the Kind-ID + * @param rid the Resource-ID + * @return the life time + */ + public int getLifeTime(KindId kid, ResourceId rid) throws ReloadException{ + + int pos = indexOf(kid, rid); + + if(pos == -1) + return -1; + + else + return life_time.get(pos); + + } + + /** + * Returns if a stored value exists. + * @param kid the Kind-ID + * @param rid the Resource-ID + * @return true if exists, false if not + */ + public boolean getExists(KindId kid, ResourceId rid) throws ReloadException{ + + int pos = indexOf(kid, rid); + + if(pos == -1) + return false; + + else + return exists.get(pos); + + } + + /** + * Returns a stored value. + * @param kid the Kind-ID + * @param rid the Resource-ID + * @return the stored value in an Opaque object + */ + public Opaque getValue(KindId kid, ResourceId rid) throws ReloadException{ + + int pos = indexOf(kid, rid); + + if(pos == -1) + return null; + + else + return value.get(pos); + + } + + /** + * Deletes a row from the table. + * @param kid the Kind-ID + * @param rid the Resource-ID + * @return true if could be deleted + */ + public synchronized boolean delete(KindId kid, ResourceId rid) throws ReloadException{ + + int pos = indexOf(kid, rid); + + if(pos == -1) + return false; + + remove(pos); + + Module.si.resource_kind.delete(kid, rid); + + if(!Module.si.resource_kind.contains(rid)) + Module.si.resource_rep.delete(rid); + + return true; + + } + + /** + * Deletes some rows from the table. + * @param rid the Resource-ID + */ + public synchronized void delete(ResourceId rid) throws ReloadException{ + + for(int ind=0, pos=0; true; ind=pos+1){ + + pos = resourceIndexOf(rid, ind); + + if(pos == -1) + break; + + else + remove(pos--); + + } + + Module.si.resource_kind.delete(rid); + + Module.si.resource_rep.delete(rid); + + } + + private void remove(int pos){ + + kind_id.remove(pos); + resource_id.remove(pos); + storage_time.remove(pos); + life_time.remove(pos); + exists.remove(pos); + value.remove(pos); + + } + + /** + * Returns the index of the first occurrence of the specified element in the table, or -1 if the element is not found. + * @param kid the Kind-ID + * @param rid the Resource-ID + * @return the index + */ + public int indexOf(KindId kid, ResourceId rid) throws ReloadException{ + + ListIterator it; + + try{ + it = resource_id.listIterator(); + } + catch(IndexOutOfBoundsException ioobe){ + return -1; + } + + for(int i=0; it.hasNext(); i++){ + + ResourceId current = (ResourceId)it.next(); + + if(current.equals(rid)) + if(kind_id.get(i) == kid.getId()) + return i; + + } + + return -1; + + } + + /** + * Returns the index of the first occurrence of the specified Resource-ID in the table, searching forwards from pos, or returns -1 if the element is not found. + * @param o the Resource-ID + * @param pos the index to start searching from + * @return the index + */ + public int resourceIndexOf(ResourceId o, int pos) throws ReloadException{ + + ListIterator it; + + try{ + it = resource_id.listIterator(pos); + } + catch(IndexOutOfBoundsException ioobe){ + return -1; + } + + for(int i=0; it.hasNext(); i++){ + + ResourceId current = (ResourceId)it.next(); + + if(current.equals(o)) + return pos+i; + + } + + return -1; + + } + + } \ No newline at end of file diff --git a/reload/Storage/StorageInterface.java b/reload/Storage/StorageInterface.java new file mode 100644 index 0000000..330a9c9 --- /dev/null +++ b/reload/Storage/StorageInterface.java @@ -0,0 +1,800 @@ + +package reload.Storage; + +import reload.Storage.Data.*; +import reload.Storage.Task.*; +import reload.Message.*; +import reload.Message.Forwarding.Destination; +import reload.Common.*; +import reload.Common.Error.*; +import reload.Common.Exception.*; +import reload.Message.Security.*; +import reload.Message.Security.TLS.*; + +import java.util.*; +import java.security.MessageDigest; + +/** +* StorageInterface class is the interface of the Storage module. +* @author Malosa +* @version 0.1 +*/ + +public class StorageInterface{ + + public KindModelList kind_model; + public KindCounterList kind_counter; + public ResourceReplicaList resource_rep; + public ResourceKindList resource_kind; + public SingleValueTable single; + public ArrayTable array; + public DictionaryTable dictionary; + + private HashAlgorithm hash_alg = HashAlgorithm.sha1; + private StorageThread thread; + +/** + * Establishes the Storage module. + */ + public StorageInterface(){ // Common=false + + kind_model = new KindModelList(); + kind_counter = new KindCounterList(); + resource_kind = new ResourceKindList(); + resource_rep = new ResourceReplicaList(); + single = new SingleValueTable(); + array = new ArrayTable(); + dictionary = new DictionaryTable(); + + thread = new StorageThread(); + + } + +/** + * Establishes the Storage module, specifying a common DataModel. + * @param common only this data model will be available + */ + public StorageInterface(DataModel common){ //Common=true + + this(); + + kind_model = new KindModelList(common); + + } + +/** + * Stores a dictionary entry in the overlay. + * @param res the Resource-ID where it will be stored + * @param replicaDest if a replica, the node-ID when it will be stores + * @param replicaNum if a replica, the replica_number value (0 if not replica) + * @param kind the kind-ID for the storage + * @param data the data to be stored + * @param key the key of the dictionary entry + */ + public void storeDictionary(ResourceId res, NodeId replicaDest, byte replicaNum, KindId kind, Opaque[] data, Opaque[] key) throws Exception{ + + boolean[] exists = new boolean[key.length]; + + for(int i=0; i unknown = new ArrayList(); + + + NodeId[] replica = new NodeId[0]; + + + for(int i=0; i queue; + private boolean empty; + private DataStructure[][] ds; + + + public StorageThread(){ + + queue = new ArrayDeque(); + empty = true; + + } + + public void run() { + + + while(true){ + + synchronized(this){ + + if(isEmpty()){ + + try{ + wait(); + } + catch(InterruptedException e){ + + e.printStackTrace(); + + } + + } + } + + try{ + + StorageTask task = queue.getFirst(); + TaskType type = task.getType(); + + synchronized(Module.si){ + + switch(type.getValue()){ + + case 0: + throw new WrongTypeReloadException("Undefined Task"); + case 1: + JoiningStoreTask stor = (JoiningStoreTask)task; + stor.start(); + break; + case 2: + AppStoreTask store = (AppStoreTask)task; + store.start(); + break; + case 3: + AppFetchTask fetch = (AppFetchTask)task; + ds = fetch.start(); + Module.si.notify(); + break; + default: + throw new WrongTypeReloadException(); + } + } + + queue.removeFirst(); + + } + catch(Exception e){ + + e.printStackTrace(); + + } + + + } + + } + + public boolean isEmpty(){ + + return queue.size() == 0; + + } + + public void add(StorageTask task){ + + queue.add(task); + + } + + public StorageTask getFirst(){ + + return queue.getFirst(); + + } + + public DataStructure[][] getDataStructure(){ + + return ds; + + } + + public void setMessage(Message message){ + + queue.getFirst().setMessage(message); + + } + + } + diff --git a/reload/Storage/Task/AppFetchTask.java b/reload/Storage/Task/AppFetchTask.java new file mode 100644 index 0000000..da2183e --- /dev/null +++ b/reload/Storage/Task/AppFetchTask.java @@ -0,0 +1,145 @@ + package reload.Storage.Task; + + import reload.Message.*; + import reload.Message.Forwarding.Destination; + import reload.Storage.*; + import reload.Storage.Data.*; + import reload.Common.*; + import reload.Common.Exception.*; + import java.util.*; + + public class AppFetchTask extends StorageTask{ + + private Destination[] destination; + private FetchReq req; + + + public AppFetchTask(StorageThread thread, Destination[] destination, FetchReq req){ + + super(thread); + + type = TaskType.app_fetch; + + this.destination = destination; + this.req = req; + + } + + public DataStructure[][] start() throws Exception{ + + Id[] id = new Id[destination.length]; + + try{ + + for(int i=0; imax) + max = index; + + } + + return max; + + } + + } + diff --git a/reload/Storage/Task/AppStoreTask.java b/reload/Storage/Task/AppStoreTask.java new file mode 100644 index 0000000..a64a4ef --- /dev/null +++ b/reload/Storage/Task/AppStoreTask.java @@ -0,0 +1,86 @@ + package reload.Storage.Task; + + import reload.Message.*; + import reload.Message.Forwarding.Destination; + import reload.Storage.*; + import reload.Storage.Data.*; + import reload.Common.*; + import reload.Common.Exception.*; + import java.util.*; + + public class AppStoreTask extends StorageTask{ + + private Destination[] destination; + private StoreReq req; + + + public AppStoreTask(StorageThread thread, Destination[] destination, StoreReq req){ + + super(thread); + + type = TaskType.app_store; + + this.destination = destination; + this.req = req; + + } + + public Object start() throws Exception{ + + Id[] id = new Id[destination.length]; + + try{ + + for(int i=0; i movingRes = store(); + + if(movingRes.size() > 0) + deleteOldData(movingRes); + + update(); + + + return null; + + } + + private ArrayList store() throws Exception{ + + ResourceId[] storedRes = Module.si.resource_kind.getResources(); + ArrayList movingRes = new ArrayList(); + + for(int i=0; i movingRes) throws ReloadException{ + + + for(int z=0; z nodeC; // NodeId, node=true + private ArrayList addressC; // IpAddressPort, node=false + private ArrayList num_linkC; + + private ArrayList nodeS; // NodeId, node=true + private ArrayList addressS; // IpAddressPort, node=false + private ArrayList num_linkS; + + + /** + * Creates a new empty table. + */ + public ChordConnectionTable(){ + + nodeC = new ArrayList(); + addressC = new ArrayList(); + num_linkC = new ArrayList(); + + nodeS = new ArrayList(); + addressS = new ArrayList(); + num_linkS = new ArrayList(); + + } + + /** + * Adds a new row to the table. + * @param node the node to be added + * @param address the IP address and port to be added + * @param client true if connection is client, false if is server + * @return the connection number (link number) + */ + public synchronized int addEntry(NodeId node, IpAddressPort address, boolean client) throws Exception{ + + byte[] Bnode = node.getBytes(); // Is equal to getId() + byte[] Baddress = address.getBytes(); + byte[] onlyAddress = address.getAddressBytes(); + int num = getFirstNumber(client); + + if(client){ + nodeC.add(Bnode); + addressC.add(Baddress); + num_linkC.add(num); + } + + else{ // Server + nodeS.add(Bnode); + addressS.add(onlyAddress); + num_linkS.add(num); + } + + return num; + + } + + /** + * Returns the link number of a stored ID. + * @param id the Node-ID we are looking for + * @param client true if connection is client, false if is server + * @return connection number (link number) + */ + public int getNumLink(Id id, boolean client){ + + if(id == null) + return -1; + + byte[] Bid = id.getId(); + + int pos = indexOf(true, client, Bid); + + if(pos == -1) + return -1; + + if(client) + return num_linkC.get(pos); + else + return num_linkS.get(pos); + + } + + /** + * Returns the link number of a stored ID. For server only. + * @param addr the IP address we are looking for + * @return connection number (link number) + */ + public int getNumLink(InetAddress addr) throws Exception{ // For SERVER Only + + IpAddressPort ip = new IpAddressPort(addr, 0); + + byte[] Bip = ip.getAddressBytes(); + + int pos = indexOf(false, false, Bip); + + if(pos == -1) + return -1; + else + return num_linkS.get(pos); + + } + + /** + * Returns the link number of a stored ID. For client only. + * @param ip the IP address and port we are looking for + * @return connection number (link number) + */ + public int getNumLink(IpAddressPort ip) throws IOException{ // For CLIENT only. Not used (at the moment) + + byte[] Bip = ip.getBytes(); + + int pos = indexOf(false, true, Bip); + + if(pos == -1) + return -1; + else + return num_linkC.get(pos); + + } + + /** + * Returns if the connection of a stored Node-ID is client or server. + * @param id the Node-ID we are asking for + * @return true if client, false if server + */ + public boolean isClient(Id id){ + + byte[] Bid = id.getId(); + + int pos = indexOf(true, true, Bid); + + if(pos == -1) + return false; + else + return true; + + } + + /** + * Returns if the connection of a stored Node-ID is client or server. + * @param id the Node-ID we are asking for + * @return true if server, false if client + */ + public boolean isServer(Id id){ + + byte[] Bid = id.getId(); + + int pos = indexOf(true, false, Bid); + + if(pos == -1) + return false; + else + return true; + + } + + private boolean exists(Id id){ + + byte[] Bid = id.getId(); + + int server = indexOf(true, false, Bid); + int client = indexOf(true, true, Bid); + + if(server == -1 && client == -1) + return false; + else + return true; + + } + + /** + * Returns the Node-ID of a stored connection. + * @param num the connection number (link number) + * @param client true if connection is client, false if is server + * @return the Node-ID + */ + public synchronized NodeId getNode(int num, boolean client) throws Exception{ + + + if(client){ + + int pos = num_linkC.indexOf(num); + if(pos != -1) + return new NodeId(nodeC.get(pos), true); // Upper + else + return null; + } + + else{ + + int pos = num_linkS.indexOf(num); + if(pos != -1) + return new NodeId(nodeS.get(pos), true); // Upper + else + return null; + } + + } + + /** + * Deletes a row from the table. + * @param node the Node-ID to be deleted + * @return true if could be deleted + */ + public boolean delete(NodeId node){ + + boolean client = isClient(node); + + return delete(node, client); + + } + + public synchronized boolean delete(NodeId node, boolean client){ + + byte[] Bid = node.getId(); + + int pos = indexOf(true, client, Bid); + + if(pos == -1) + return false; + + try{ + remove(pos, client); + } + catch(IndexOutOfBoundsException e){ + return false; + } + + return true; + + } + + /** + * Deletes a row from the table. + * @param num the connection number (link number) + * @param client true if connection is client, false if is server + * @return true if could be deleted + */ + public synchronized boolean delete(int num, boolean client){ + + int del_num = -1; + + if(client) + del_num = num_linkC.indexOf(num); + + else + del_num = num_linkS.indexOf(num); + + + if(del_num == -1) + return false; + + try{ + remove(del_num, client); + } + catch(IndexOutOfBoundsException e){ + return false; + } + + return true; + + } + + private void remove(int num, boolean client) throws IndexOutOfBoundsException{ + + if(client){ + + nodeC.remove(num); + addressC.remove(num); + num_linkC.remove(num); + } + + else{ + + nodeS.remove(num); + addressS.remove(num); + num_linkS.remove(num); + } + + } + + /** + * Returns the IP address and port of a stored connection. + * @param num the connection number (link number) + * @param client true if connection is client, false if is server + * @return the IP address and port (client) or the IP address only (server) + */ + public synchronized IpAddressPort getAddressPort(int num, boolean client) throws Exception{ + + + if(client){ + + int pos = num_linkC.indexOf(num); + if(pos != -1) + return new IpAddressPort(addressC.get(pos)); + else + return null; + } + + else{ // Server + + int pos = num_linkS.indexOf(num); + if(pos != -1) + return new IpAddressPort(addressS.get(pos), 0); // No remote port when I am acting server + else + return null; + } + + } + + /** + * Returns the number of client or server links that exist in the connection table. + * @param client true for the client links number, false for the server links number + * @return the number of links + */ + public int getNumLinks(boolean client){ + + if (client) + return nodeC.size(); + + else + return nodeS.size(); + + } + + /** + * Returns if a Node-ID exists in the connection table. + * @param node the Node-ID + * @return true if exists, false if not + */ + public boolean isDirectlyConnected(NodeId node){ + + return exists(node); + + } + + // Separar en dos: nodeIndexOf y addrIndexOf + private synchronized int indexOf(boolean node, boolean client, byte[] data){ + + if(client){ + + if(node){ + + for (int i=0; i Math.pow(2, 16)-1) + throw new WrongLengthReloadException(); + + pred_length = 0; + predecessors = new NodeId[0]; + } + else{ + predecessors = node; + type = ChordLeaveType.from_pred; + for (int i=0; i Math.pow(2, 16)-1) + throw new WrongLengthReloadException(); + + succ_length = 0; + successors = new NodeId[0]; + } + } + + + public ChordLeaveData (NodeId[] node, ChordLeaveType type) throws Exception{ + + this.type = type; + + switch(type.getBytes()){ + case 1: //Successors + successors = node; + for (int i=0; i Math.pow(2, 16)-1) + throw new WrongLengthReloadException(); + + pred_length = 0; + predecessors = new NodeId[0]; + break; + case 2: //Predeccesors + predecessors = node; + for (int i=0; i Math.pow(2, 16)-1) + throw new WrongLengthReloadException(); + + succ_length = 0; + successors = new NodeId[0]; + break; + default: + throw new WrongTypeReloadException(); + } + + } + + public ChordLeaveData (byte[] data) throws Exception{ + + type = ChordLeaveType.valueOf(data[0]); + + switch(type.getBytes()){ + + case 1: + succ_length = Utils.toShort(data, 1); + + if(succ_length % NodeId.getLength() != 0) + throw new WrongLengthReloadException(); + + int num_succ = succ_length / NodeId.getLength(); + successors = new NodeId[num_succ]; + int offset = 3; + for (int i=0; i list) throws Exception{ + + BigInteger min = new BigInteger(1, NodeId.ones); // MAX_VALUE + NodeId best = null; + + // We find the min distance from the peer to the destId + for(int i=0; i list){ + + BigInteger diff = new BigInteger(1, NodeId.ones); // MAX_VALUE + NodeId best = null; + + for(int i=0; i list = orderPosAlgorithm(candidate); + + if(list.get(predecessor.length).equals(node)) // If the middle of the list is node + return false; + else + return true; + + } + + /** + * Tries to store a node into the Neighbor Table. It only will be added to the table if it is a better value than the stored nodes. + * @param node the node to be stored + * @return true if the node were added + */ + public boolean addNeighborAndReturn(NodeId node) throws ReloadException{ + + if(exists(node)) + return false; + + NodeId[] candidates = getNeighborsAndCandidate(node); + + return neighborAlgorithm(candidates, true); + + } + + /** + * Tries to store a node into the Neighbor Table. It only will be added to the table if it has a closer distance than the stored nodes. There is not return value. + * @param node the node to be stored + */ + public void addNeighbor(NodeId node) throws ReloadException{ + + if(exists(node)) + return; + + if(getSuccessorLength() == successor.length && getPredecessorLength() == predecessor.length) + if(getCurrentFingerLength() != finger.length) + Module.falm.createAttachFingersRoute(); + + NodeId[] candidates = getNeighborsAndCandidate(node); + + neighborAlgorithm(candidates, false); + + } + + private boolean neighborAlgorithm(NodeId[] candidate, boolean isVoid) throws ReloadException{ + + NodeId[] succ1 = getSuccessors().clone(); + NodeId[] pred1 = getPredecessors().clone(); + + ArrayList list = orderAbsAlgorithm(candidate); + + + boolean pred_full = false, succ_full = false; + ArrayList excess_p = new ArrayList(); + ArrayList excess_s = new ArrayList(); + + int max; + if(list.size() > (predecessor.length + successor.length)) + max = predecessor.length; + else if(list.size()%2 == 0) + max = list.size()/2; + else + max = list.size()/2 + 1; + + int p=0, s=0; + for(int i=0; i 0 && !pred_full){ + + for(int i=excess_p.size()-1; i>=0 && p 0 && !succ_full){ + + for(int i=excess_s.size()-1; i>=0 && s orderAbsAlgorithm(NodeId[] candidate){ + + ArrayList list = new ArrayList(); + + boolean added; + + for(int i=0; i orderPosAlgorithm(NodeId[] candidate){ + + ArrayList list = new ArrayList(); + + boolean added; + + for(int i=0; i previousID. If not, comparation is an OR || + + if(resource.gt(previousID) && resource.lte(thisID)) // Responsible ID + return true; + + else // Other ID + return false; + + } + + else{ // thisId < previousID + + if(resource.gt(previousID) || resource.lte(thisID)) // Responsible ID + return true; + + else // Other ID + return false; + + } + + } + + /** + * Checks if a joining node is responsible for a Resource-ID. This is only for a special case when a new Node-ID is joining the overlay. It does not work in the general case. + * @param resource the Resource-ID from which we want to know the responsibility + * @param joining the responsible joining Node-ID + * @return true if the joining node is responsible + */ + public boolean isResponsible(NodeId joining, ResourceId resource) throws ReloadException{ // Node is responsible from resource + + NodeId thisID = getThisNode(); + + NodeId previousID = getPredecessor(0); + + if(previousID == null){ // Only node in overlay + + if(getSuccessor(0) != null) // Two nodes in the overlay + previousID = getSuccessor(0); + else + previousID = thisID; // You are your own predecessor + } + + if(joining.gt(previousID)){ // If thisID > previousID. If not, comparation is an OR || + + if(resource.gt(previousID) && resource.lte(joining)) // Responsible ID + return true; + + else // Other ID + return false; + + } + + else{ // thisId < previousID + + if(resource.gt(previousID) || resource.lte(joining)) // Responsible ID + return true; + + else // Other ID + return false; + + } + + } + + /** + * Returns the number of valid successors stored in the Neighbor Table. + * @return the number of successors stored + */ + public int getSuccessorLength(){ + + for(int i=0; i getNodes(){ // Potencially not scalable + + ArrayList list = new ArrayList(); + + for(int i=0; i + private short succ_length; + private NodeId[] successors; //<0..2^16-1> + private short fing_length; + private NodeId[] fingers; //<0..2^16-1> + + + public ChordUpdateReq (int uptime){ + + this.uptime = uptime; + type = ChordUpdateType.peer_ready; + + pred_length=0; + succ_length=0; + fing_length=0; + + predecessors = new NodeId[0]; + successors = new NodeId[0]; + fingers = new NodeId[0]; + + } + + public ChordUpdateReq (int uptime, NodeId[] predecessors, NodeId[] successors) throws Exception{ + + this.predecessors = predecessors; + this.successors = successors; + this.uptime = uptime; + type = ChordUpdateType.neighbors; + + for (int i=0; i Math.pow(2, 16)-1) + throw new WrongLengthReloadException(); + + for (int i=0; i Math.pow(2, 16)-1) + throw new WrongLengthReloadException(); + + fing_length=0; + fingers = new NodeId[0]; + + } + + public ChordUpdateReq (int uptime, NodeId[] predecessors, NodeId[] successors, NodeId[] fingers) throws Exception{ + + this(uptime, predecessors, successors); + this.fingers = fingers; + type = ChordUpdateType.full; + + for (int i=0; i Math.pow(2, 16)-1) + throw new WrongLengthReloadException(); + + } + + public ChordUpdateReq (byte[] data) throws Exception{ + + uptime = Utils.toInt(data, 0); + type = ChordUpdateType.valueOf(data[4]); + + switch(type.getBytes()){ + + case 1: + pred_length=0; + succ_length=0; + fing_length=0; + + predecessors = new NodeId[0]; + successors = new NodeId[0]; + fingers = new NodeId[0]; + break; + + case 2: + pred_length = Utils.toShort(data, 5); + + if(pred_length % NodeId.getLength() != 0) + throw new WrongLengthReloadException(); + + int num_pred = pred_length / NodeId.getLength(); + predecessors = new NodeId[num_pred]; + + int offset = 7; + + for (int i=0; i node = Module.tpi.routingTable.getNodes(); + + for(int i=0; i list) throws Exception{ + + return routing.route(thisId, destId, list); + + } + + public ResourceId closest(ResourceId[] value, ResourceId ideal){ + + return routing.closest(value, ideal); + + } + + public ResourceId distanceFinger(NodeId thisId, int i) throws Exception{ + + return routing.distanceFinger(thisId, i); + + } + +/** + * Method to be called by the Topology Plugin when it receives a Chord Update Request message. + * @param msg_body Chord Update Request message to decode + * @param src peer which the message comes from (not the creator, just the last hop) + * @return the response (Chord Update Answer) to the request + */ + public byte[] update_req(byte[] msg_body, NodeId src) throws Exception{ + + + ChordUpdateReq req = new ChordUpdateReq(msg_body); + + int uptime = req.getUptime(); + + ChordUpdateType type = req.getType(); + + if (!Module.falm.updateIntialization){ + + if(type == ChordUpdateType.peer_ready){ + + if(!Module.tpi.routingTable.exists(src)) + if(Module.tpi.connectionTable.isDirectlyConnected(src)){ + Module.tpi.createUpdate(src, (byte)1); // peer_ready + Module.tpi.routingTable.addNeighbor(src); + } + + } + + if(type == ChordUpdateType.neighbors){ + NodeId[] predecessors = req.getPredecessors(); + NodeId[] successors = req.getSuccessors(); + Module.falm.createAttachRoute(predecessors, successors, false); + } + + if(type == ChordUpdateType.full){ + NodeId[] predecessors = req.getPredecessors(); + NodeId[] successors = req.getSuccessors(); + NodeId[] fingers = req.getFingers(); + Module.falm.createAttachRoute(predecessors, successors, fingers, false); + } + + } + + else{ // Module.falm.updateIntialization=true + + Module.tpi.routingTable.addNeighbor(src); // Admitting Peer ID (AP) + + if(type == ChordUpdateType.full){ + NodeId[] predecessors = req.getPredecessors(); + NodeId[] successors = req.getSuccessors(); + Module.falm.createAttachRoute(predecessors, successors, false); + + NodeId[] fingers = req.getFingers(); + Module.falm.createAttachRoute(fingers, true); // Fingers only + } + + else if(type == ChordUpdateType.neighbors){ + NodeId[] predecessors = req.getPredecessors(); + NodeId[] successors = req.getSuccessors(); + Module.falm.createAttachRoute(predecessors, successors, true); + + Module.falm.createAttachFingersRoute(); // If type is neighbor, make attachs to fingers + } + + else + throw new WrongTypeReloadException(); + + Module.falm.updateIntialization = false; + + } + + ChordUpdateAns ans = new ChordUpdateAns(true); + + if(Module.falm.joinIntialization){ // Special case for initialization + Module.falm.joinIntialization = false; + synchronized(Module.falm){ + Module.falm.notify(); + } + } + + return ans.getBytes(); + + } + +/** + * Method to be called by the Topology Plugin when it receives a Chord Join Request message. + * @param msg_body Chord Join Request message to decode + * @param src peer which the message comes from (not the creator, just the last hop) + * @return the response (Chord Join Answer) to the request + */ + public byte[] join_req(byte[] msg_body, NodeId src) throws Exception{ + + ChordJoinReq req = new ChordJoinReq(msg_body); + + NodeId id = req.getJoiningPeerId(); + + if(!src.equals(id)) + throw new ErrorForbidden(); + + + boolean client = Module.tpi.connectionTable.isClient(id); + int numLink = Module.tpi.connectionTable.getNumLink(id, client); + + + Module.si.createJoiningStore(id, numLink, client); + + + ChordJoinAns ans = new ChordJoinAns(); + + return ans.getBytes(); + + } + +/** + * Method to be called by the Topology Plugin when it receives a Chord Leave Request message. + * @param msg_body Chord Leave Request message to decode + * @param src peer which the message comes from (not the creator, just the last hop) + * @return the response (Chord Leave Answer) to the request + */ + public byte[] leave_req(byte[] msg_body, NodeId src) throws Exception{ + + ChordLeaveReq req = new ChordLeaveReq(msg_body); + + NodeId id = req.getLeavingPeerId(); + + ChordLeaveData data = req.getLeavingData(); + + ChordLeaveType type = data.getType(); + + if(type == ChordLeaveType.from_succ){ + NodeId[] successor = data.getSuccessors(); + } + + if(type == ChordLeaveType.from_pred){ + NodeId[] predecessor = data.getPredecessors(); + } + + if(!src.equals(id)) + throw new ErrorForbidden(); + + if(!Module.tpi.connectionTable.isDirectlyConnected(id)) + throw new ErrorForbidden(); + + + Module.tpi.routingTable.delete(id); + + + ChordLeaveAns ans = new ChordLeaveAns(); + + return ans.getBytes(); + + } + +/* + * Method to be called by the Topology Plugin when it receives a Chord Route Query Request message. + * @param msg_body Chord Route Query Request message to decode + * @return the response (Chord Route Query Answer) to the request + */ + public byte[] route_query_req(byte[] msg_body) throws Exception{ + + + ChordRouteQueryReq req = new ChordRouteQueryReq(msg_body); + + boolean send_update = req.getSendUpdate(); + Destination destination = req.getDestination(); + + if(send_update){ + + } + + NodeId next_peer = null; + + DestinationData data = destination.getDestinationData(); + DestinationType type = destination.getType(); + + if(type == DestinationType.opaque_id_type) + throw new UnimplementedReloadException("Opaque/compressed List"); + + else{ + Id dest = data.getId(); + next_peer = Module.tpi.route(dest); + } + + ChordRouteQueryAns ans = new ChordRouteQueryAns(next_peer); + + return ans.getBytes(); + + } + +/** + * Creates an Update Task. + * @param dest Node-ID to send the Update to + * @param numLink the link number + * @param client true if connection is client, false if is server + * @param updateType ChordUpdateType for the request + * @param sendData data will be sent when link is up + */ + public void createUpdate(NodeId dest, int numLink, boolean client, byte updateType, boolean sendData){ + + ChordUpdateTask task; + + if(dest == null) + task = new ChordUpdateTask(thread); + + else{ + + if(sendData) + task = new ChordUpdateTask(thread, dest, numLink, client, ChordUpdateType.valueOf(updateType)); + + else + task = new ChordUpdateTask(thread, dest, ChordUpdateType.valueOf(updateType)); + + } + + synchronized(thread){ + + boolean empty = thread.isEmpty(); + + thread.add(task); + + if(empty) + thread.notify(); + + } + + } + +/** + * Creates a Join Task. + * @param dest the Admitting Peer Node-ID + */ + public void createJoin(NodeId dest){ + + ChordJoinTask task = new ChordJoinTask(thread, dest); + + synchronized(thread){ + + boolean empty = thread.isEmpty(); + + thread.add(task); + + if(empty) + thread.notify(); + + } + + } + +/** + * Creates a Leave Task. + */ + public void createLeave(){ + + ChordLeaveTask task = new ChordLeaveTask(thread); + + synchronized(thread){ + + boolean empty = thread.isEmpty(); + + thread.add(task); + + if(empty) + thread.notify(); + + } + + } + +/** + * Generates a new Node-ID or Resource-ID from the IP address (used if no enrollment server exists). + * @param address the IP address (port is not used) + * @param node true if Node-ID, false if Resource-ID + */ + public Id generateNewId(InetAddress address, boolean node) throws Exception{ // Port is not used + + IpAddressPort IpAddr = new IpAddressPort(address, 0); + + MessageDigest md = MessageDigest.getInstance(Module.falm.getConfiguration().getDigest()); // sha1 or sha256 (SHA-1 by default) + md.update(IpAddr.getAddressBytes()); + byte[] ID = md.digest(); + ID = Utils.cutArray(ID, 16, 0); + + if(node) + return new NodeId(ID, true); + else + return new ResourceId(ID, true); // Upper + + } + +/** + * Calculates the hash of a String, obtaining a Reource-ID with the most significant 128 bits. + * @param name the String + * @return the Resource-ID calculated. + */ + public ResourceId hash(String name) throws Exception{ + + MessageDigest md = MessageDigest.getInstance(Module.falm.getConfiguration().getDigest()); // sha1 or sha256 (SHA-1 by default) + md.update(name.getBytes("US-ASCII")); + byte[] ID = md.digest(); + ID = Utils.cutArray(ID, 16, 0); + + return new ResourceId(ID, true); // Upper + + } + +/** + * Returns the Topology Plugin thread. + * @return the TopologyThread object. + */ + public ChordThread getChordThread(){ + + return thread; + + } + +} \ No newline at end of file diff --git a/reload/Topology/Plugins/ChordThread.java b/reload/Topology/Plugins/ChordThread.java new file mode 100644 index 0000000..4adf59b --- /dev/null +++ b/reload/Topology/Plugins/ChordThread.java @@ -0,0 +1,113 @@ +package reload.Topology.Plugins; + +import reload.Message.*; +import reload.Topology.Plugins.Chord.Task.*; +import reload.Common.*; +import reload.Common.Exception.*; + +import java.util.*; + + +public class ChordThread extends Thread { + + + private ArrayDeque queue; + + private boolean empty; + + + + public ChordThread(){ + + queue = new ArrayDeque(); + + empty = true; + + } + + public void run() { + + + while(true){ + + synchronized(this){ + + if(isEmpty()){ + + try{ + wait(); + } + catch(InterruptedException e){ + + e.printStackTrace(); + + } + + } + } + + try{ + + ChordTask task = queue.getFirst(); + ChordTaskType type = task.getType(); + + switch(type.getValue()){ + + case 0: + throw new WrongTypeReloadException("Undefined Task"); + case 1: + ChordUpdateTask update = (ChordUpdateTask)task; + update.start(); + break; + case 2: + ChordLeaveTask leave = (ChordLeaveTask)task; + leave.start(); + break; + case 3: + ChordJoinTask join = (ChordJoinTask)task; + join.start(); + break; + default: + throw new WrongTypeReloadException(); + } + + queue.removeFirst(); + + } + catch(Exception e){ + + e.printStackTrace(); + + } + + + } + + } + + public boolean isEmpty(){ + + return queue.size() == 0; + + } + + public void add(ChordTask task){ + + queue.add(task); + + } + + public ChordTask getFirst(){ + + return queue.getFirst(); + + } + + public void setMessage(Message message){ + + queue.getFirst().setMessage(message); + + } + +} + diff --git a/reload/Topology/Plugins/ProbeAns.java b/reload/Topology/Plugins/ProbeAns.java new file mode 100644 index 0000000..547febc --- /dev/null +++ b/reload/Topology/Plugins/ProbeAns.java @@ -0,0 +1,65 @@ + package reload.Topology.Plugins; + + import java.io.*; + import reload.Common.*; + import reload.Common.Exception.*; + + public class ProbeAns{ + + + private short probe_length; + private ProbeInformation[] probe_info; //<0..2^16-1> + + + public ProbeAns (ProbeInformation probe_info[]) throws Exception{ + + this.probe_info = probe_info; + + for (int i=0; i Math.pow(2, 16)-1) + throw new WrongLengthReloadException(); + + } + + public ProbeAns (byte[] data) throws Exception{ + + probe_length = Utils.toShort(data, 0); + + Utils.cutArray(data, probe_length, 2); + int offset = 0; + + int num = Algorithm.counter(1, data, 1); + + probe_info = new ProbeInformation[num]; + + for (int i=0; i Math.pow(2, 8)-1) + throw new WrongLengthReloadException(); + + } + + public ProbeReq (byte[] data){ + + probe_length = data[0]; + + data = Utils.cutArray(data, probe_length, 1); + + requested_info = new ProbeInformationType[probe_length]; + + for (int i=0; i getNodes(){ + + return chord.getNodes(); + + } + + public NodeId[] getPredecessors(){ + + return chord.getPredecessors(); + + } + + public NodeId[] getSuccessors(){ + + return chord.getSuccessors(); + + } + + public NodeId[] getNodesForReplicas(){ + + return chord.getTwoSuccessors(); + + } + + public NodeId[] getFingersForSending(){ + + return chord.getFingersForSending(); + + } + + public NodeId[] getFingers(){ + + return chord.getFingers(); + + } + + public String printNeighbors(){ + + return chord.printNeighbors(); + + } + + public String printFingers(){ + + return chord.printFingers(); + + } + + public String printId() throws Exception{ + + return chord.printId(); + + } + + } \ No newline at end of file diff --git a/reload/Topology/TopologyPluginInterface.java b/reload/Topology/TopologyPluginInterface.java new file mode 100644 index 0000000..07c56d9 --- /dev/null +++ b/reload/Topology/TopologyPluginInterface.java @@ -0,0 +1,235 @@ +package reload.Topology; + +import java.io.*; +import reload.Common.*; +import reload.Common.Error.*; +import reload.Topology.Plugins.*; +import reload.Topology.Plugins.Chord.Task.*; +import reload.Message.Forwarding.Destination; +import java.net.InetAddress; + +/** +* TopologyPluginInterface class is the interface of the TopologyPlugin module. +* @author Malosa +* @version 0.1 +*/ +public class TopologyPluginInterface{ + + public RoutingTable routingTable; + public ConnectionTable connectionTable; + + public boolean nodeJoiningFlag; + + //private AnotherOne other_plugin; + private ChordInterface chord; + + private int responsible_ppb=0, num_resources=0, uptime=0; // Pending + + +/** + * Establishes the Topology Plugin module. + */ + public TopologyPluginInterface(){ + + routingTable = new RoutingTable(); + connectionTable = new ConnectionTable(); + + chord = new ChordInterface(); + + } + + public Id generateNewId(InetAddress address, boolean node) throws Exception{ // Port is not used. Only for Chord + + return chord.generateNewId(address, node); + + } + + public ResourceId hash(String name) throws Exception{ // Only for Chord + + return chord.hash(name); + + } + +/** + * Gets the next hop when a message is routed to a destination ID. + * @param destId the destination ID (Node-ID or Resource-ID) + * @return next hop's Node-ID + */ + public NodeId route(Id destId) throws Exception{ + + return chord.route(routingTable.getThisNode(), destId, routingTable.getNodes()); + + } + +/** + * Gets the next hop when a message is routed to a destination list. + * @param destId the destination ID list (Node-ID array or Resource-ID array) + * @return next hop's Node-ID + */ + public NodeId route(Id[] destId) throws Exception{ + + return route(destId[0]); + + } + + public ResourceId closest(ResourceId[] value, ResourceId ideal){ + + return chord.closest(value, ideal); + + } + + public ResourceId distanceFinger(int i) throws Exception{ + + return chord.distanceFinger(routingTable.getThisNode(), i); + + } + + public byte[] createJoinReq(NodeId node) throws java.io.IOException{ + + return chord.createJoinReq(node); + + } + +/** + * Method to be called by Message Transport when it receives a Probe Request message. + * @param msg_body Probe Request message to decode + * @return the response (Probe Answer) to the request + */ + public byte[] probe_req(byte[] msg_body) throws Exception{ + + + ProbeReq req = new ProbeReq(msg_body); + + ProbeInformationType[] type = req.getRequestedInfo(); + + ProbeInformation[] pi = new ProbeInformation[type.length]; + + for(int i=0; i 0) + { + err.println("tThere are " + numSuppressed + " suppressed exceptions:"); + for (final Throwable exception : suppressedExceptions) + { + err.println("tt" + exception.toString()); + } + } + + /* Experimental */ + + return; + } + + + + } + + } diff --git a/reload/dev2dev/lib/concurrent.jar b/reload/dev2dev/lib/concurrent.jar new file mode 100644 index 0000000..26cb11e Binary files /dev/null and b/reload/dev2dev/lib/concurrent.jar differ diff --git a/reload/dev2dev/lib/jain-sdp-1.0.2337.jar b/reload/dev2dev/lib/jain-sdp-1.0.2337.jar new file mode 100644 index 0000000..60a2e63 Binary files /dev/null and b/reload/dev2dev/lib/jain-sdp-1.0.2337.jar differ diff --git a/reload/dev2dev/lib/jain-sdp-src-1.0.2337.jar b/reload/dev2dev/lib/jain-sdp-src-1.0.2337.jar new file mode 100644 index 0000000..d1e4c52 Binary files /dev/null and b/reload/dev2dev/lib/jain-sdp-src-1.0.2337.jar differ diff --git a/reload/dev2dev/lib/jain-sip-api-1.2-src.jar b/reload/dev2dev/lib/jain-sip-api-1.2-src.jar new file mode 100644 index 0000000..7c4646b Binary files /dev/null and b/reload/dev2dev/lib/jain-sip-api-1.2-src.jar differ diff --git a/reload/dev2dev/lib/jain-sip-api-1.2.jar b/reload/dev2dev/lib/jain-sip-api-1.2.jar new file mode 100644 index 0000000..ab6bdbd Binary files /dev/null and b/reload/dev2dev/lib/jain-sip-api-1.2.jar differ diff --git a/reload/dev2dev/lib/jain-sip-ri-1.2.2337.jar b/reload/dev2dev/lib/jain-sip-ri-1.2.2337.jar new file mode 100644 index 0000000..ed15209 Binary files /dev/null and b/reload/dev2dev/lib/jain-sip-ri-1.2.2337.jar differ diff --git a/reload/dev2dev/lib/jain-sip-sdp-1.2.2337.jar b/reload/dev2dev/lib/jain-sip-sdp-1.2.2337.jar new file mode 100644 index 0000000..1c1f6a2 Binary files /dev/null and b/reload/dev2dev/lib/jain-sip-sdp-1.2.2337.jar differ diff --git a/reload/dev2dev/lib/jain-sip-src-1.2.2337.jar b/reload/dev2dev/lib/jain-sip-src-1.2.2337.jar new file mode 100644 index 0000000..8eb7234 Binary files /dev/null and b/reload/dev2dev/lib/jain-sip-src-1.2.2337.jar differ diff --git a/reload/dev2dev/lib/jain-sip-tck-1.2.2337.jar b/reload/dev2dev/lib/jain-sip-tck-1.2.2337.jar new file mode 100644 index 0000000..0f7a216 Binary files /dev/null and b/reload/dev2dev/lib/jain-sip-tck-1.2.2337.jar differ diff --git a/reload/dev2dev/lib/log4j-1.2.17.jar b/reload/dev2dev/lib/log4j-1.2.17.jar new file mode 100644 index 0000000..068867e Binary files /dev/null and b/reload/dev2dev/lib/log4j-1.2.17.jar differ diff --git a/reload/dev2dev/textclient/MessageProcessor.java b/reload/dev2dev/textclient/MessageProcessor.java new file mode 100644 index 0000000..97a2e52 --- /dev/null +++ b/reload/dev2dev/textclient/MessageProcessor.java @@ -0,0 +1,8 @@ + package reload.dev2dev.textclient; + + public interface MessageProcessor{ + + public void processMessage(String sender, String message); + public void processError(String errorMessage); + public void processInfo(String infoMessage); + } diff --git a/reload/dev2dev/textclient/SipLayer.java b/reload/dev2dev/textclient/SipLayer.java new file mode 100644 index 0000000..11c7247 --- /dev/null +++ b/reload/dev2dev/textclient/SipLayer.java @@ -0,0 +1,272 @@ + package reload.dev2dev.textclient; + + import java.net.InetAddress; + import java.text.ParseException; + import java.util.ArrayList; + import java.util.Properties; + import java.util.TooManyListenersException; + + import javax.sip.DialogTerminatedEvent; + import javax.sip.IOExceptionEvent; + import javax.sip.InvalidArgumentException; + import javax.sip.ListeningPoint; + import javax.sip.ObjectInUseException; + import javax.sip.PeerUnavailableException; + import javax.sip.RequestEvent; + import javax.sip.ResponseEvent; + import javax.sip.ServerTransaction; + import javax.sip.SipException; + import javax.sip.SipFactory; + import javax.sip.SipListener; + import javax.sip.SipProvider; + import javax.sip.SipStack; + import javax.sip.TimeoutEvent; + import javax.sip.TransactionTerminatedEvent; + import javax.sip.TransportNotSupportedException; + import javax.sip.address.Address; + import javax.sip.address.AddressFactory; + import javax.sip.address.SipURI; + import javax.sip.header.CSeqHeader; + import javax.sip.header.CallIdHeader; + import javax.sip.header.ContactHeader; + import javax.sip.header.ContentTypeHeader; + import javax.sip.header.FromHeader; + import javax.sip.header.HeaderFactory; + import javax.sip.header.MaxForwardsHeader; + import javax.sip.header.ToHeader; + import javax.sip.header.ViaHeader; + import javax.sip.message.MessageFactory; + import javax.sip.message.Request; + import javax.sip.message.Response; + + public class SipLayer implements SipListener { + + private MessageProcessor messageProcessor; + + private String username; + + private SipStack sipStack; + + private SipFactory sipFactory; + + private AddressFactory addressFactory; + + private HeaderFactory headerFactory; + + private MessageFactory messageFactory; + + private SipProvider sipProvider; + + private String name; + + //private ListeningPoint tcp; + private ListeningPoint udp; + + /** Here we initialize the SIP stack. */ + public SipLayer(String ip, int port, String name) + throws PeerUnavailableException, TransportNotSupportedException, + InvalidArgumentException, ObjectInUseException, + TooManyListenersException { + + this.name = name; + setUsername(username); + sipFactory = SipFactory.getInstance(); + sipFactory.setPathName("gov.nist"); + Properties properties = new Properties(); + properties.setProperty("javax.sip.STACK_NAME", "TextClient"); + properties.setProperty("javax.sip.IP_ADDRESS", ip); + + //DEBUGGING: Information will go to files + //textclient.log and textclientdebug.log + /* properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "32"); + properties.setProperty("gov.nist.javax.sip.SERVER_LOG", + "textclient.txt"); + properties.setProperty("gov.nist.javax.sip.DEBUG_LOG", + "textclientdebug.log");*/ + + sipStack = sipFactory.createSipStack(properties); + headerFactory = sipFactory.createHeaderFactory(); + addressFactory = sipFactory.createAddressFactory(); + messageFactory = sipFactory.createMessageFactory(); + + //tcp = sipStack.createListeningPoint(ip, port, "tcp"); + udp = sipStack.createListeningPoint(ip, port, "udp"); + + //sipProvider = sipStack.createSipProvider(tcp); + //sipProvider.addSipListener(this); + sipProvider = sipStack.createSipProvider(udp); + sipProvider.addSipListener(this); + } + + /** + * This method uses the SIP stack to send a message. + */ + public void sendMessage(String to, String message) throws ParseException, + InvalidArgumentException, SipException { + + SipURI from = addressFactory.createSipURI(null, name+ ":" + getPort()); + Address fromNameAddress = addressFactory.createAddress(from); + fromNameAddress.setDisplayName(getUsername()); + FromHeader fromHeader = headerFactory.createFromHeader(fromNameAddress, + "textclientv1.0"); + + String username = to.substring(to.indexOf(":") + 1, to.indexOf("@")); + String address = to.substring(to.indexOf("@") + 1); + + SipURI toAddress = addressFactory.createSipURI(username, address); + Address toNameAddress = addressFactory.createAddress(toAddress); + toNameAddress.setDisplayName(username); + ToHeader toHeader = headerFactory.createToHeader(toNameAddress, null); + + SipURI requestURI = addressFactory.createSipURI(username, address); + requestURI.setTransportParam("udp"); + + ArrayList viaHeaders = new ArrayList(); + ViaHeader viaHeader = headerFactory.createViaHeader(getHost(), + getPort(), "udp", "branch1"); + viaHeaders.add(viaHeader); + + CallIdHeader callIdHeader = sipProvider.getNewCallId(); + + CSeqHeader cSeqHeader = headerFactory.createCSeqHeader(1L, + Request.MESSAGE); + + MaxForwardsHeader maxForwards = headerFactory + .createMaxForwardsHeader(70); + + Request request = messageFactory.createRequest(requestURI, + Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader, + toHeader, viaHeaders, maxForwards); + + SipURI contactURI = addressFactory.createSipURI(getUsername(), + getHost()); + contactURI.setPort(getPort()); + Address contactAddress = addressFactory.createAddress(contactURI); + contactAddress.setDisplayName(getUsername()); + ContactHeader contactHeader = headerFactory + .createContactHeader(contactAddress); + request.addHeader(contactHeader); + + ContentTypeHeader contentTypeHeader = headerFactory + .createContentTypeHeader("text", "plain"); + request.setContent(message, contentTypeHeader); + + sipProvider.sendRequest(request); + } + + /** This method is called by the SIP stack when a response arrives. */ + public void processResponse(ResponseEvent evt) { + Response response = evt.getResponse(); + int status = response.getStatusCode(); + + if ((status >= 200) && (status < 300)) { //Success! + messageProcessor.processInfo("--Sent"); + return; + } + + messageProcessor.processError("Previous message not sent: " + status); + } + + /** + * This method is called by the SIP stack when a new request arrives. + */ + public void processRequest(RequestEvent evt) { + Request req = evt.getRequest(); + + String method = req.getMethod(); + if (!method.equals("MESSAGE")) { //bad request type. + messageProcessor.processError("Bad request type: " + method); + return; + } + + FromHeader from = (FromHeader) req.getHeader("From"); + messageProcessor.processMessage(from.getAddress().toString(), //Aquí está la clave de todo + new String(req.getRawContent())); + Response response = null; + try { //Reply with OK + response = messageFactory.createResponse(200, req); + ToHeader toHeader = (ToHeader) response.getHeader(ToHeader.NAME); + toHeader.setTag("888"); //This is mandatory as per the spec. + ServerTransaction st = sipProvider.getNewServerTransaction(req); + st.sendResponse(response); + } + catch (Throwable e) { + e.printStackTrace(); + messageProcessor.processError("Can't send OK reply."); + } + } + + /** + * This method is called by the SIP stack when there's no answer + * to a message. Note that this is treated differently from an error + * message. + */ + public void processTimeout(TimeoutEvent evt) { + messageProcessor + .processError("Previous message not sent: " + "timeout"); + } + + /** + * This method is called by the SIP stack when there's an asynchronous + * message transmission error. + */ + public void processIOException(IOExceptionEvent evt) { + messageProcessor.processError("Previous message not sent: " + + "I/O Exception"); + } + + /** + * This method is called by the SIP stack when a dialog (session) ends. + */ + public void processDialogTerminated(DialogTerminatedEvent evt) { + } + + /** + * This method is called by the SIP stack when a transaction ends. + */ + public void processTransactionTerminated(TransactionTerminatedEvent evt) { + } + + public String getHost() { + int port = sipProvider.getListeningPoints()[0].getPort(); + String host = sipStack.getIPAddress(); + return host; + } + + public int getPort() { + int port = sipProvider.getListeningPoints()[0].getPort(); + return port; + } + + public String getUsername() { + return username; + } + + public void setUsername(String newUsername) { + username = newUsername; + } + + public MessageProcessor getMessageProcessor() { + return messageProcessor; + } + + public void setMessageProcessor(MessageProcessor newMessageProcessor) { + messageProcessor = newMessageProcessor; + } + + public void close(){ + + try{ + //sipStack.deleteListeningPoint(tcp); + sipStack.deleteListeningPoint(udp); + sipProvider.removeSipListener(this); + } + catch (Exception e){ + + System.err.println("Error on close in Text Client."); + + } + + } + + } diff --git a/reload/dev2dev/textclient/TextClient.java b/reload/dev2dev/textclient/TextClient.java new file mode 100644 index 0000000..81abcfd --- /dev/null +++ b/reload/dev2dev/textclient/TextClient.java @@ -0,0 +1,140 @@ + package reload.dev2dev.textclient; + + import java.awt.event.*; + import java.net.*; + import java.text.ParseException; + import java.util.*; + + import javax.sip.*; + import javax.sip.address.*; + import javax.sip.header.*; + import javax.sip.header.ToHeader; + import javax.sip.header.ViaHeader; + import javax.sip.message.*; + import javax.swing.*; + + public class TextClient + extends JFrame + implements MessageProcessor + { + private SipLayer sipLayer; + + private JTextField fromAddress; + private JLabel fromLbl; + private JLabel receivedLbl; + private JTextArea receivedMessages; + private JScrollPane receivedScrollPane; + private JButton sendBtn; + private JLabel sendLbl; + private JTextField sendMessages; + private JTextField toAddress; + private JLabel toLbl; + + private final String from; // = "sip:marcos@192.168.1.1:9999"; + private final String to; // = "sip:isabel@192.168.1.70:9999"; + + + + public TextClient(SipLayer sip, String from, String to){ + + super(); + + this.from = from; + this.to = to; + + sipLayer = sip; + initWindow(); + } + + private void initWindow() { + receivedLbl = new JLabel(); + sendLbl = new JLabel(); + sendMessages = new JTextField(); + receivedScrollPane = new JScrollPane(); + receivedMessages = new JTextArea(); + + sendBtn = new JButton(); + + getContentPane().setLayout(null); + + setTitle("TextClient"); + + addWindowListener( + new WindowAdapter() { + public void windowClosing(WindowEvent evt) { + sipLayer.close(); + } + }); + + receivedLbl.setText("Received Messages:"); + receivedLbl.setAlignmentY(0.0F); + receivedLbl.setPreferredSize(new java.awt.Dimension(25, 100)); + getContentPane().add(receivedLbl); + receivedLbl.setBounds(5, 0, 136, 20); + + sendLbl.setText("Send Message:"); + getContentPane().add(sendLbl); + sendLbl.setBounds(5, 150, 90, 20); + + getContentPane().add(sendMessages); + sendMessages.setBounds(5, 170, 270, 20); + + receivedMessages.setAlignmentX(0.0F); + receivedMessages.setEditable(false); + receivedMessages.setLineWrap(true); + receivedMessages.setWrapStyleWord(true); + receivedScrollPane.setViewportView(receivedMessages); + receivedScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + + getContentPane().add(receivedScrollPane); + receivedScrollPane.setBounds(5, 20, 270, 130); + + + sendBtn.setText("Send"); + sendBtn.addActionListener( + new ActionListener() { + public void actionPerformed(ActionEvent evt) { + sendBtnActionPerformed(evt); + } + }); + + getContentPane().add(sendBtn); + sendBtn.setBounds(200, 200, 75, 25); + + java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize(); + setBounds((screenSize.width-288)/2, (screenSize.height-310)/2, 295, 275); + } + + private void sendBtnActionPerformed(ActionEvent evt) { + + try + { + String message = this.sendMessages.getText(); + sipLayer.sendMessage(to, message); + } + catch (Throwable e) + { + e.printStackTrace(); + this.receivedMessages.append("ERROR sending message: " + e.getMessage() + "\n"); + } + + } + + public void processMessage(String sender, String message) + { + this.receivedMessages.append("From " + + sender + ": " + message + "\n"); + } + + public void processError(String errorMessage) + { + this.receivedMessages.append("ERROR: " + + errorMessage + "\n"); + } + + public void processInfo(String infoMessage) + { + this.receivedMessages.append( + infoMessage + "\n"); + } + } diff --git a/reload/gpl-3.0.txt b/reload/gpl-3.0.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/reload/gpl-3.0.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/reload/overlay.xml b/reload/overlay.xml new file mode 100644 index 0000000..5b82654 --- /dev/null +++ b/reload/overlay.xml @@ -0,0 +1,55 @@ + + + + CHORD-RELOAD + 16 + MIIDJDCCAo2gAwIBAgIBADANBgkqhkiG9w0BAQUFADBwMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTERMA8GA1UEBxMIU2FuIEpvc2UxDjAMBgNVBAoTBXNpcGl0MSkwJwYDVQQLEyBTaXBpdCBUZXN0IENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0wMzA3MTgxMjIxNTJaFw0xMzA3MTUxMjIxNTJaMHAxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMREwDwYDVQQHEwhTYW4gSm9zZTEOMAwGA1UEChMFc2lwaXQxKTAnBgNVBAsTIFNpcGl0IFRlc3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDIh6DkcUDLDyK9BEUxkud+nJ4xrCVGKfgjHm6XaSuHiEtnfELHM+9WymzkBNzZpJu30yzsxwfKoIKugdNUrD4N3viCicwcN35LgP/KnbN34cavXHr4ZlqxH+OdKB3hQTpQa38A7YXdaoz6goW2ft5Mi74z03GNKP/G9BoKOGd5QIDAQABo4HNMIHKMB0GA1UdDgQWBBRrRhcU6pR2JYBUbhNU2qHjVBShtjCBmgYDVR0jBIGSMIGPgBRrRhcU6pR2JYBUbhNU2qHjVBShtqF0pHIwcDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExETAPBgNVBAcTCFNhbiBKb3NlMQ4wDAYDVQQKEwVzaXBpdDEpMCcGA1UECxMgU2lwaXQgVGVzdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQCWbRvv1ZGTRXxbH8/EqkdSCzSoUPrs+rQqR0xdQac9wNY/nlZbkR3OqAezG6Sfmklvf+DOg5RxQq/+Y6I03LRepc7KeVDpaplMFGnpfKsibETMipwzayNQQgUf4cKBiF+65Ue7hZuDJa2EMv8qW4twEhGDYclpFU9YozyS1OhvUg== + YmFkIGNlcnQK + https://example.org + https://example.net + false + + + 20 + + + false + false + 400 + 30 + true + password + 4000 + 30 + 3000 + TCP + 47112162e84c69ba + 47112162e84c69ba + 6eba45d31a900c06 + 6ebc45d31a900c06 + 6ebc45d31a900ca6 + foo + urn:ietf:params:xml:ns:p2p:config-ext1 + + + + + SINGLE + USER-MATCH + 1 + 100 + ARRAY + NODE-MULTIPLE + 3 + 22 + 4 + 1 + + VGhpcyBpcyBub3QgcmlnaHQhCg== + + + + VGhpcyBpcyBub3QgcmlnaHQhCg== + + VGhpcyBpcyBub3QgcmlnaHQhCg== +