/*******************************************************************************
* gMix open source project - https://svs.informatik.uni-hamburg.de/gmix/
* Copyright (C) 2014 SVS
*
* 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 <http://www.gnu.org/licenses/>.
*******************************************************************************/
package staticContent.framework.routing;
import java.net.InetAddress;
import java.security.SecureRandom;
import java.util.Arrays;
import staticContent.framework.util.Util;
public class MixList {
public int numberOfMixes;
public int[] mixIDs;
public InetAddress[] addresses;
public int[] ports;
private static SecureRandom random = new SecureRandom();
public MixList() {
}
public InetAddress getAddress(int mixID) {
for (int i=0; i<mixIDs.length; i++)
if (mixIDs[i] == mixID)
return addresses[i];
return null;
}
public int getPort(int mixID) {
for (int i=0; i<mixIDs.length; i++)
if (mixIDs[i] == mixID)
return ports[i];
return -1;
}
public int getMixID(InetAddress address) {
for (int i=0; i<addresses.length; i++)
if (addresses[i].equals(address))
return mixIDs[i];
return -1;
}
public int getMixID(InetAddress address, int port) {
for (int i=0; i<addresses.length; i++)
if (addresses[i].equals(address) && ports[i] == port)
return mixIDs[i];
return -1;
}
public MixList getRandomRoute() {
int hops = random.nextInt(mixIDs.length-2) + 1;
return getRandomRoute(hops);
}
public MixList getRandomRoute(int numberOfMixes) {
if (numberOfMixes > this.numberOfMixes)
throw new RuntimeException("not enough mixes available for the route length specified (" +numberOfMixes +">" + this.numberOfMixes +")");
MixList randomRoute = new MixList();
randomRoute.numberOfMixes = numberOfMixes;
randomRoute.mixIDs = new int[numberOfMixes];
Arrays.fill(randomRoute.mixIDs, Util.NOT_SET);
randomRoute.addresses = new InetAddress[numberOfMixes];
randomRoute.ports = new int[numberOfMixes];
for (int i=0; i<randomRoute.numberOfMixes; i++) {
int pos;
do { // get (unused) mix id at random
pos = random.nextInt(this.numberOfMixes);
} while (Util.contains(pos, randomRoute.mixIDs));
randomRoute.mixIDs[i] = mixIDs[pos];
randomRoute.addresses[i] = addresses[pos];
randomRoute.ports[i] = ports[pos];
}
return randomRoute;
}
public MixList getRandomRoute(int numberOfMixes, int finalHopId) {
if (numberOfMixes > this.numberOfMixes)
throw new RuntimeException("not enough mixes available for the route length specified (" +numberOfMixes +">" + this.numberOfMixes +")");
MixList randomRoute = new MixList();
randomRoute.numberOfMixes = numberOfMixes;
randomRoute.mixIDs = new int[numberOfMixes];
Arrays.fill(randomRoute.mixIDs, Util.NOT_SET);
randomRoute.addresses = new InetAddress[numberOfMixes];
randomRoute.ports = new int[numberOfMixes];
for (int i=0; i<randomRoute.numberOfMixes-1; i++) {
int pos;
do { // get (unused) mix id at random
pos = random.nextInt(this.numberOfMixes);
} while (Util.contains(pos, mixIDs));
randomRoute.mixIDs[i] = randomRoute.mixIDs[pos];
randomRoute.addresses[i] = addresses[pos];
randomRoute.ports[i] = ports[pos];
}
int finalHopPos = Util.NOT_SET;
for (int i=0; i<mixIDs.length; i++) {
if (mixIDs[i] == finalHopId) {
finalHopPos = i;
break;
}
}
assert finalHopPos != Util.NOT_SET;
randomRoute.mixIDs[randomRoute.mixIDs.length-1] = mixIDs[finalHopPos];
randomRoute.addresses[randomRoute.addresses.length-1] = addresses[finalHopPos];
randomRoute.ports[randomRoute.ports.length-1] = ports[finalHopPos];
return randomRoute;
}
public int getRandomMixId() {
int pos = Util.getRandomInt(0, mixIDs.length-1, random);
return mixIDs[pos];
}
public static byte[] packIdArray(int[] ids) {
byte[][] chunks = new byte[ids.length][];
for (int i=0; i<ids.length; i++)
chunks[i] = Util.intToByteArray(ids[i]);
return Util.concatArrays(chunks);
}
public static int[] unpackIdArray(byte[] ids) {
byte[][] chunks = Util.split(4, ids);
int[] result = new int[chunks.length];
for (int i=0; i<chunks.length; i++)
result[i] = Util.byteArrayToInt(chunks[i]);
return result;
}
public static byte[] packIdArray(int[] route, short pos) {
UnpackedIdArray idObj = new UnpackedIdArray();
idObj.route = Arrays.copyOfRange(route, 1, route.length);
idObj.pos = pos;
return packIdArray(idObj);
}
public static byte[] packIdArray(UnpackedIdArray idObj) {
byte[][] chunks = new byte[idObj.route.length][];
for (int i=0; i<idObj.route.length; i++) {
assert idObj.route[i] != Util.NOT_SET;
chunks[i] = Util.intToByteArray(idObj.route[i]);
}
byte[] result = Util.concatArrays(
Util.shortToByteArray(idObj.pos),
Util.concatArrays(chunks)
);
return result;
}
public static UnpackedIdArray unpackIdArrayWithPos(byte[] ids) {
UnpackedIdArray result = new UnpackedIdArray();
byte[][] posAndRest = Util.split(2, ids);
result.pos = Util.byteArrayToShort(posAndRest[0]);
byte[][] chunks = Util.splitInChunks(4, posAndRest[1]);
result.route = new int[chunks.length];
for (int i=0; i<chunks.length; i++)
result.route[i] = Util.byteArrayToInt(chunks[i]);
return result;
}
@Override
public String toString() {
return "MixList (" +this.hashCode() +"): "
+numberOfMixes +" mixes; ids: "
+Arrays.toString(mixIDs) +"; addresses: "
+Arrays.toString(addresses) +"; ports: "
+Arrays.toString(ports);
}
}